diff options
22 files changed, 627 insertions, 455 deletions
diff --git a/docs/API/differences_in_mastoapi_responses.md b/docs/API/differences_in_mastoapi_responses.md index 06de90f71..476a4a2bf 100644 --- a/docs/API/differences_in_mastoapi_responses.md +++ b/docs/API/differences_in_mastoapi_responses.md @@ -180,7 +180,7 @@ Post here request with grant_type=refresh_token to obtain new access token. Retu  ## Account Registration  `POST /api/v1/accounts` -Has theses additionnal parameters (which are the same as in Pleroma-API): +Has theses additional parameters (which are the same as in Pleroma-API):      * `fullname`: optional      * `bio`: optional      * `captcha_solution`: optional, contains provider-specific captcha solution, diff --git a/docs/clients.md b/docs/clients.md index 8ac9ad3de..1eae0f0c6 100644 --- a/docs/clients.md +++ b/docs/clients.md @@ -1,5 +1,5 @@  # Pleroma Clients -Note: Additionnal clients may be working but theses are officially supporting Pleroma. +Note: Additional clients may be working but theses are officially supporting Pleroma.  Feel free to contact us to be added to this list!  ## Desktop diff --git a/lib/pleroma/plugs/ensure_authenticated_plug.ex b/lib/pleroma/plugs/ensure_authenticated_plug.ex index 6f9b840a9..054d2297f 100644 --- a/lib/pleroma/plugs/ensure_authenticated_plug.ex +++ b/lib/pleroma/plugs/ensure_authenticated_plug.ex @@ -15,9 +15,24 @@ defmodule Pleroma.Plugs.EnsureAuthenticatedPlug do      conn    end -  def call(conn, _) do +  def call(conn, options) do +    perform = +      cond do +        options[:if_func] -> options[:if_func].() +        options[:unless_func] -> !options[:unless_func].() +        true -> true +      end + +    if perform do +      fail(conn) +    else +      conn +    end +  end + +  def fail(conn) do      conn      |> render_error(:forbidden, "Invalid credentials.") -    |> halt +    |> halt()    end  end diff --git a/lib/pleroma/plugs/federating_plug.ex b/lib/pleroma/plugs/federating_plug.ex index d3943586d..7d947339f 100644 --- a/lib/pleroma/plugs/federating_plug.ex +++ b/lib/pleroma/plugs/federating_plug.ex @@ -10,14 +10,20 @@ defmodule Pleroma.Web.FederatingPlug do    end    def call(conn, _opts) do -    if Pleroma.Config.get([:instance, :federating]) do +    if federating?() do        conn      else -      conn -      |> put_status(404) -      |> Phoenix.Controller.put_view(Pleroma.Web.ErrorView) -      |> Phoenix.Controller.render("404.json") -      |> halt() +      fail(conn)      end    end + +  def federating?, do: Pleroma.Config.get([:instance, :federating]) + +  defp fail(conn) do +    conn +    |> put_status(404) +    |> Phoenix.Controller.put_view(Pleroma.Web.ErrorView) +    |> Phoenix.Controller.render("404.json") +    |> halt() +  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 779de0e4d..8b9eb4a2c 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -9,6 +9,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do    alias Pleroma.Delivery    alias Pleroma.Object    alias Pleroma.Object.Fetcher +  alias Pleroma.Plugs.EnsureAuthenticatedPlug    alias Pleroma.User    alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.Web.ActivityPub.InternalFetchActor @@ -18,23 +19,37 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do    alias Pleroma.Web.ActivityPub.UserView    alias Pleroma.Web.ActivityPub.Utils    alias Pleroma.Web.ActivityPub.Visibility +  alias Pleroma.Web.FederatingPlug    alias Pleroma.Web.Federator    require Logger    action_fallback(:errors) +  @federating_only_actions [:internal_fetch, :relay, :relay_following, :relay_followers] + +  plug(FederatingPlug when action in @federating_only_actions) + +  plug( +    EnsureAuthenticatedPlug, +    [unless_func: &FederatingPlug.federating?/0] when action not in @federating_only_actions +  ) + +  plug( +    EnsureAuthenticatedPlug +    when action in [:read_inbox, :update_outbox, :whoami, :upload_media, :following, :followers] +  ) +    plug(      Pleroma.Plugs.Cache,      [query_params: false, tracking_fun: &__MODULE__.track_object_fetch/2]      when action in [:activity, :object]    ) -  plug(Pleroma.Web.FederatingPlug when action in [:inbox, :relay])    plug(:set_requester_reachable when action in [:inbox])    plug(:relay_active? when action in [:relay]) -  def relay_active?(conn, _) do +  defp relay_active?(conn, _) do      if Pleroma.Config.get([:instance, :allow_relay]) do        conn      else @@ -127,11 +142,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do    end    # GET /relay/following -  def following(%{assigns: %{relay: true}} = conn, _params) do -    conn -    |> put_resp_content_type("application/activity+json") -    |> put_view(UserView) -    |> render("following.json", %{user: Relay.get_actor()}) +  def relay_following(conn, _params) do +    with %{halted: false} = conn <- FederatingPlug.call(conn, []) do +      conn +      |> put_resp_content_type("application/activity+json") +      |> put_view(UserView) +      |> render("following.json", %{user: Relay.get_actor()}) +    end    end    def following(%{assigns: %{user: for_user}} = conn, %{"nickname" => nickname, "page" => page}) do @@ -164,11 +181,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do    end    # GET /relay/followers -  def followers(%{assigns: %{relay: true}} = conn, _params) do -    conn -    |> put_resp_content_type("application/activity+json") -    |> put_view(UserView) -    |> render("followers.json", %{user: Relay.get_actor()}) +  def relay_followers(conn, _params) do +    with %{halted: false} = conn <- FederatingPlug.call(conn, []) do +      conn +      |> put_resp_content_type("application/activity+json") +      |> put_view(UserView) +      |> render("followers.json", %{user: Relay.get_actor()}) +    end    end    def followers(%{assigns: %{user: for_user}} = conn, %{"nickname" => nickname, "page" => page}) do @@ -200,13 +219,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do      end    end -  def outbox(conn, %{"nickname" => nickname, "page" => page?} = params) +  def outbox( +        %{assigns: %{user: for_user}} = conn, +        %{"nickname" => nickname, "page" => page?} = params +      )        when page? in [true, "true"] do      with %User{} = user <- User.get_cached_by_nickname(nickname),           {:ok, user} <- User.ensure_keys_present(user) do        activities =          if params["max_id"] do -          ActivityPub.fetch_user_activities(user, nil, %{ +          ActivityPub.fetch_user_activities(user, for_user, %{              "max_id" => params["max_id"],              # This is a hack because postgres generates inefficient queries when filtering by              # 'Answer', poll votes will be hidden by the visibility filter in this case anyway @@ -214,7 +236,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do              "limit" => 10            })          else -          ActivityPub.fetch_user_activities(user, nil, %{ +          ActivityPub.fetch_user_activities(user, for_user, %{              "limit" => 10,              "include_poll_votes" => true            }) @@ -255,8 +277,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do      json(conn, "ok")    end -  # only accept relayed Creates -  def inbox(conn, %{"type" => "Create"} = params) do +  # POST /relay/inbox -or- POST /internal/fetch/inbox +  def inbox(conn, params) do +    if params["type"] == "Create" && FederatingPlug.federating?() do +      post_inbox_relayed_create(conn, params) +    else +      post_inbox_fallback(conn, params) +    end +  end + +  defp post_inbox_relayed_create(conn, params) do      Logger.debug(        "Signature missing or not from author, relayed Create message, fetching object from source"      ) @@ -266,10 +296,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do      json(conn, "ok")    end -  def inbox(conn, params) do +  defp post_inbox_fallback(conn, params) do      headers = Enum.into(conn.req_headers, %{}) -    if String.contains?(headers["signature"], params["actor"]) do +    if headers["signature"] && params["actor"] && +         String.contains?(headers["signature"], params["actor"]) do        Logger.debug(          "Signature validation error for: #{params["actor"]}, make sure you are forwarding the HTTP Host header!"        ) @@ -277,7 +308,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do        Logger.debug(inspect(conn.req_headers))      end -    json(conn, dgettext("errors", "error")) +    conn +    |> put_status(:bad_request) +    |> json(dgettext("errors", "error"))    end    defp represent_service_actor(%User{} = user, conn) do @@ -311,10 +344,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do      |> render("user.json", %{user: user})    end -  def whoami(_conn, _params), do: {:error, :not_found} -    def read_inbox( -        %{assigns: %{user: %{nickname: nickname} = user}} = conn, +        %{assigns: %{user: %User{nickname: nickname} = user}} = conn,          %{"nickname" => nickname, "page" => page?} = params        )        when page? in [true, "true"] do @@ -337,7 +368,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do      })    end -  def read_inbox(%{assigns: %{user: %{nickname: nickname} = user}} = conn, %{ +  def read_inbox(%{assigns: %{user: %User{nickname: nickname} = user}} = conn, %{          "nickname" => nickname        }) do      with {:ok, user} <- User.ensure_keys_present(user) do @@ -348,15 +379,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do      end    end -  def read_inbox(%{assigns: %{user: nil}} = conn, %{"nickname" => nickname}) do -    err = dgettext("errors", "can't read inbox of %{nickname}", nickname: nickname) - -    conn -    |> put_status(:forbidden) -    |> json(err) -  end - -  def read_inbox(%{assigns: %{user: %{nickname: as_nickname}}} = conn, %{ +  def read_inbox(%{assigns: %{user: %User{nickname: as_nickname}}} = conn, %{          "nickname" => nickname        }) do      err = @@ -370,7 +393,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do      |> json(err)    end -  def handle_user_activity(user, %{"type" => "Create"} = params) do +  defp handle_user_activity(%User{} = user, %{"type" => "Create"} = params) do      object =        params["object"]        |> Map.merge(Map.take(params, ["to", "cc"])) @@ -386,7 +409,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do      })    end -  def handle_user_activity(user, %{"type" => "Delete"} = params) do +  defp handle_user_activity(%User{} = user, %{"type" => "Delete"} = params) do      with %Object{} = object <- Object.normalize(params["object"]),           true <- user.is_moderator || user.ap_id == object.data["actor"],           {:ok, delete} <- ActivityPub.delete(object) do @@ -396,7 +419,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do      end    end -  def handle_user_activity(user, %{"type" => "Like"} = params) do +  defp handle_user_activity(%User{} = user, %{"type" => "Like"} = params) do      with %Object{} = object <- Object.normalize(params["object"]),           {:ok, activity, _object} <- ActivityPub.like(user, object) do        {:ok, activity} @@ -405,7 +428,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do      end    end -  def handle_user_activity(_, _) do +  defp handle_user_activity(_, _) do      {:error, dgettext("errors", "Unhandled activity type")}    end @@ -434,7 +457,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do      end    end -  def update_outbox(%{assigns: %{user: user}} = conn, %{"nickname" => nickname} = _) do +  def update_outbox(%{assigns: %{user: %User{} = user}} = conn, %{"nickname" => nickname}) do      err =        dgettext("errors", "can't update outbox of %{nickname} as %{as_nickname}",          nickname: nickname, @@ -446,13 +469,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do      |> json(err)    end -  def errors(conn, {:error, :not_found}) do +  defp errors(conn, {:error, :not_found}) do      conn      |> put_status(:not_found)      |> json(dgettext("errors", "Not found"))    end -  def errors(conn, _e) do +  defp errors(conn, _e) do      conn      |> put_status(:internal_server_error)      |> json(dgettext("errors", "error")) @@ -492,7 +515,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do    - HTTP Code: 201 Created    - HTTP Body: ActivityPub object to be inserted into another's `attachment` field    """ -  def upload_media(%{assigns: %{user: user}} = conn, %{"file" => file} = data) do +  def upload_media(%{assigns: %{user: %User{} = user}} = conn, %{"file" => file} = data) do      with {:ok, object} <-             ActivityPub.upload(               file, diff --git a/lib/pleroma/web/feed/user_controller.ex b/lib/pleroma/web/feed/user_controller.ex index 59aabb549..9ba602d9f 100644 --- a/lib/pleroma/web/feed/user_controller.ex +++ b/lib/pleroma/web/feed/user_controller.ex @@ -25,7 +25,12 @@ defmodule Pleroma.Web.Feed.UserController do    def feed_redirect(%{assigns: %{format: format}} = conn, _params)        when format in ["json", "activity+json"] do -    ActivityPubController.call(conn, :user) +    with %{halted: false} = conn <- +           Pleroma.Plugs.EnsureAuthenticatedPlug.call(conn, +             unless_func: &Pleroma.Web.FederatingPlug.federating?/0 +           ) do +      ActivityPubController.call(conn, :user) +    end    end    def feed_redirect(conn, %{"nickname" => nickname}) do diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex index c443c888c..6fd3cfce5 100644 --- a/lib/pleroma/web/ostatus/ostatus_controller.ex +++ b/lib/pleroma/web/ostatus/ostatus_controller.ex @@ -16,6 +16,10 @@ defmodule Pleroma.Web.OStatus.OStatusController do    alias Pleroma.Web.Metadata.PlayerView    alias Pleroma.Web.Router +  plug(Pleroma.Plugs.EnsureAuthenticatedPlug, +    unless_func: &Pleroma.Web.FederatingPlug.federating?/0 +  ) +    plug(      RateLimiter,      [name: :ap_routes, params: ["uuid"]] when action in [:object, :activity] @@ -135,13 +139,13 @@ defmodule Pleroma.Web.OStatus.OStatusController do      end    end -  def errors(conn, {:error, :not_found}) do +  defp errors(conn, {:error, :not_found}) do      render_error(conn, :not_found, "Not found")    end -  def errors(conn, {:fetch_user, nil}), do: errors(conn, {:error, :not_found}) +  defp errors(conn, {:fetch_user, nil}), do: errors(conn, {:error, :not_found}) -  def errors(conn, _) do +  defp errors(conn, _) do      render_error(conn, :internal_server_error, "Something went wrong")    end  end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 980242c68..e4e3ee704 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -541,6 +541,7 @@ defmodule Pleroma.Web.Router do      get("/mailer/unsubscribe/:token", Mailer.SubscriptionController, :unsubscribe)    end +  # Server to Server (S2S) AP interactions    pipeline :activitypub do      plug(:accepts, ["activity+json", "json"])      plug(Pleroma.Web.Plugs.HTTPSignaturePlug) @@ -554,6 +555,7 @@ defmodule Pleroma.Web.Router do      get("/users/:nickname/outbox", ActivityPubController, :outbox)    end +  # Client to Server (C2S) AP interactions    pipeline :activitypub_client do      plug(:accepts, ["activity+json", "json"])      plug(:fetch_session) @@ -597,8 +599,8 @@ defmodule Pleroma.Web.Router do        post("/inbox", ActivityPubController, :inbox)      end -    get("/following", ActivityPubController, :following, assigns: %{relay: true}) -    get("/followers", ActivityPubController, :followers, assigns: %{relay: true}) +    get("/following", ActivityPubController, :relay_following) +    get("/followers", ActivityPubController, :relay_followers)    end    scope "/internal/fetch", Pleroma.Web.ActivityPub do diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index 5ac75f1c4..5027d5c23 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -17,6 +17,10 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do    plug(:put_view, Pleroma.Web.StaticFE.StaticFEView)    plug(:assign_id) +  plug(Pleroma.Plugs.EnsureAuthenticatedPlug, +    unless_func: &Pleroma.Web.FederatingPlug.federating?/0 +  ) +    @page_keys ["max_id", "min_id", "limit", "since_id", "order"]    defp get_title(%Object{data: %{"name" => name}}) when is_binary(name), @@ -33,7 +37,7 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do      |> render("error.html", %{message: message, meta: ""})    end -  def get_counts(%Activity{} = activity) do +  defp get_counts(%Activity{} = activity) do      %Object{data: data} = Object.normalize(activity)      %{ @@ -43,9 +47,9 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do      }    end -  def represent(%Activity{} = activity), do: represent(activity, false) +  defp represent(%Activity{} = activity), do: represent(activity, false) -  def represent(%Activity{object: %Object{data: data}} = activity, selected) do +  defp represent(%Activity{object: %Object{data: data}} = activity, selected) do      {:ok, user} = User.get_or_fetch(activity.object.data["actor"])      link = @@ -147,17 +151,17 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do      end    end -  def assign_id(%{path_info: ["notice", notice_id]} = conn, _opts), +  defp assign_id(%{path_info: ["notice", notice_id]} = conn, _opts),      do: assign(conn, :notice_id, notice_id) -  def assign_id(%{path_info: ["users", user_id]} = conn, _opts), +  defp assign_id(%{path_info: ["users", user_id]} = conn, _opts),      do: assign(conn, :username_or_id, user_id) -  def assign_id(%{path_info: ["objects", object_id]} = conn, _opts), +  defp assign_id(%{path_info: ["objects", object_id]} = conn, _opts),      do: assign(conn, :object_id, object_id) -  def assign_id(%{path_info: ["activities", activity_id]} = conn, _opts), +  defp assign_id(%{path_info: ["activities", activity_id]} = conn, _opts),      do: assign(conn, :activity_id, activity_id) -  def assign_id(conn, _opts), do: conn +  defp assign_id(conn, _opts), do: conn  end diff --git a/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex b/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex index fbf31c7eb..89da760da 100644 --- a/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex @@ -16,6 +16,8 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowController do    @status_types ["Article", "Event", "Note", "Video", "Page", "Question"] +  plug(Pleroma.Web.FederatingPlug) +    # Note: follower can submit the form (with password auth) not being signed in (having no token)    plug(      OAuthScopesPlug, diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index bca0e26eb..537f9f778 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -17,6 +17,8 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do    alias Pleroma.Web.CommonAPI    alias Pleroma.Web.WebFinger +  plug(Pleroma.Web.FederatingPlug when action == :remote_subscribe) +    plug(      OAuthScopesPlug,      %{scopes: ["follow", "write:follows"]} diff --git a/test/plugs/ensure_authenticated_plug_test.exs b/test/plugs/ensure_authenticated_plug_test.exs index 18be5edd0..7f3559b83 100644 --- a/test/plugs/ensure_authenticated_plug_test.exs +++ b/test/plugs/ensure_authenticated_plug_test.exs @@ -8,24 +8,62 @@ defmodule Pleroma.Plugs.EnsureAuthenticatedPlugTest do    alias Pleroma.Plugs.EnsureAuthenticatedPlug    alias Pleroma.User -  test "it halts if no user is assigned", %{conn: conn} do -    conn = -      conn -      |> EnsureAuthenticatedPlug.call(%{}) +  describe "without :if_func / :unless_func options" do +    test "it halts if user is NOT assigned", %{conn: conn} do +      conn = EnsureAuthenticatedPlug.call(conn, %{}) -    assert conn.status == 403 -    assert conn.halted == true +      assert conn.status == 403 +      assert conn.halted == true +    end + +    test "it continues if a user is assigned", %{conn: conn} do +      conn = assign(conn, :user, %User{}) +      ret_conn = EnsureAuthenticatedPlug.call(conn, %{}) + +      assert ret_conn == conn +    end    end -  test "it continues if a user is assigned", %{conn: conn} do -    conn = -      conn -      |> assign(:user, %User{}) +  describe "with :if_func / :unless_func options" do +    setup do +      %{ +        true_fn: fn -> true end, +        false_fn: fn -> false end +      } +    end + +    test "it continues if a user is assigned", %{conn: conn, true_fn: true_fn, false_fn: false_fn} do +      conn = assign(conn, :user, %User{}) +      assert EnsureAuthenticatedPlug.call(conn, if_func: true_fn) == conn +      assert EnsureAuthenticatedPlug.call(conn, if_func: false_fn) == conn +      assert EnsureAuthenticatedPlug.call(conn, unless_func: true_fn) == conn +      assert EnsureAuthenticatedPlug.call(conn, unless_func: false_fn) == conn +    end + +    test "it continues if a user is NOT assigned but :if_func evaluates to `false`", +         %{conn: conn, false_fn: false_fn} do +      assert EnsureAuthenticatedPlug.call(conn, if_func: false_fn) == conn +    end + +    test "it continues if a user is NOT assigned but :unless_func evaluates to `true`", +         %{conn: conn, true_fn: true_fn} do +      assert EnsureAuthenticatedPlug.call(conn, unless_func: true_fn) == conn +    end + +    test "it halts if a user is NOT assigned and :if_func evaluates to `true`", +         %{conn: conn, true_fn: true_fn} do +      conn = EnsureAuthenticatedPlug.call(conn, if_func: true_fn) + +      assert conn.status == 403 +      assert conn.halted == true +    end -    ret_conn = -      conn -      |> EnsureAuthenticatedPlug.call(%{}) +    test "it halts if a user is NOT assigned and :unless_func evaluates to `false`", +         %{conn: conn, false_fn: false_fn} do +      conn = EnsureAuthenticatedPlug.call(conn, unless_func: false_fn) -    assert ret_conn == conn +      assert conn.status == 403 +      assert conn.halted == true +    end    end  end diff --git a/test/plugs/oauth_plug_test.exs b/test/plugs/oauth_plug_test.exs index 8534a5c13..f74c068cd 100644 --- a/test/plugs/oauth_plug_test.exs +++ b/test/plugs/oauth_plug_test.exs @@ -38,7 +38,7 @@ defmodule Pleroma.Plugs.OAuthPlugTest do      assert conn.assigns[:user] == opts[:user]    end -  test "with valid token(downcase) in url parameters, it assings the user", opts do +  test "with valid token(downcase) in url parameters, it assigns the user", opts do      conn =        :get        |> build_conn("/?access_token=#{opts[:token]}") diff --git a/test/support/conn_case.ex b/test/support/conn_case.ex index 0f2e81f9e..064874201 100644 --- a/test/support/conn_case.ex +++ b/test/support/conn_case.ex @@ -26,6 +26,8 @@ defmodule Pleroma.Web.ConnCase do        use Pleroma.Tests.Helpers        import Pleroma.Web.Router.Helpers +      alias Pleroma.Config +        # The default endpoint for testing        @endpoint Pleroma.Web.Endpoint @@ -48,6 +50,28 @@ defmodule Pleroma.Web.ConnCase do          %{user: user, token: token, conn: conn}        end + +      defp ensure_federating_or_authenticated(conn, url, user) do +        initial_setting = Config.get([:instance, :federating]) +        on_exit(fn -> Config.put([:instance, :federating], initial_setting) end) + +        Config.put([:instance, :federating], false) + +        conn +        |> get(url) +        |> response(403) + +        conn +        |> assign(:user, user) +        |> get(url) +        |> response(200) + +        Config.put([:instance, :federating], true) + +        conn +        |> get(url) +        |> response(200) +      end      end    end diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs index b2352538a..bd8e0b5cc 100644 --- a/test/web/activity_pub/activity_pub_controller_test.exs +++ b/test/web/activity_pub/activity_pub_controller_test.exs @@ -8,6 +8,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do    import Pleroma.Factory    alias Pleroma.Activity +  alias Pleroma.Config    alias Pleroma.Delivery    alias Pleroma.Instances    alias Pleroma.Object @@ -25,9 +26,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do      :ok    end -  clear_config_all([:instance, :federating], -    do: Pleroma.Config.put([:instance, :federating], true) -  ) +  clear_config([:instance, :federating]) do +    Config.put([:instance, :federating], true) +  end    describe "/relay" do      clear_config([:instance, :allow_relay]) @@ -42,12 +43,21 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do      end      test "with the relay disabled, it returns 404", %{conn: conn} do -      Pleroma.Config.put([:instance, :allow_relay], false) +      Config.put([:instance, :allow_relay], false) + +      conn +      |> get(activity_pub_path(conn, :relay)) +      |> json_response(404) +    end + +    test "on non-federating instance, it returns 404", %{conn: conn} do +      Config.put([:instance, :federating], false) +      user = insert(:user)        conn +      |> assign(:user, user)        |> get(activity_pub_path(conn, :relay))        |> json_response(404) -      |> assert      end    end @@ -60,6 +70,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do        assert res["id"] =~ "/fetch"      end + +    test "on non-federating instance, it returns 404", %{conn: conn} do +      Config.put([:instance, :federating], false) +      user = insert(:user) + +      conn +      |> assign(:user, user) +      |> get(activity_pub_path(conn, :internal_fetch)) +      |> json_response(404) +    end    end    describe "/users/:nickname" do @@ -123,9 +143,34 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do        assert json_response(conn, 404)      end + +    test "it returns error when user is not found", %{conn: conn} do +      response = +        conn +        |> put_req_header("accept", "application/json") +        |> get("/users/jimm") +        |> json_response(404) + +      assert response == "Not found" +    end + +    test "it requires authentication if instance is NOT federating", %{ +      conn: conn +    } do +      user = insert(:user) + +      conn = +        put_req_header( +          conn, +          "accept", +          "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"" +        ) + +      ensure_federating_or_authenticated(conn, "/users/#{user.nickname}.json", user) +    end    end -  describe "/object/:uuid" do +  describe "/objects/:uuid" do      test "it returns a json representation of the object with accept application/json", %{        conn: conn      } do @@ -236,6 +281,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do        assert "Not found" == json_response(conn2, :not_found)      end + +    test "it requires authentication if instance is NOT federating", %{ +      conn: conn +    } do +      user = insert(:user) +      note = insert(:note) +      uuid = String.split(note.data["id"], "/") |> List.last() + +      conn = put_req_header(conn, "accept", "application/activity+json") + +      ensure_federating_or_authenticated(conn, "/objects/#{uuid}", user) +    end    end    describe "/activities/:uuid" do @@ -307,6 +364,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do        assert "Not found" == json_response(conn2, :not_found)      end + +    test "it requires authentication if instance is NOT federating", %{ +      conn: conn +    } do +      user = insert(:user) +      activity = insert(:note_activity) +      uuid = String.split(activity.data["id"], "/") |> List.last() + +      conn = put_req_header(conn, "accept", "application/activity+json") + +      ensure_federating_or_authenticated(conn, "/activities/#{uuid}", user) +    end    end    describe "/inbox" do @@ -379,6 +448,34 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do        :ok = Mix.Tasks.Pleroma.Relay.run(["list"])        assert_receive {:mix_shell, :info, ["relay.mastodon.host"]}      end + +    test "without valid signature, " <> +           "it only accepts Create activities and requires enabled federation", +         %{conn: conn} do +      data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!() +      non_create_data = File.read!("test/fixtures/mastodon-announce.json") |> Poison.decode!() + +      conn = put_req_header(conn, "content-type", "application/activity+json") + +      Config.put([:instance, :federating], false) + +      conn +      |> post("/inbox", data) +      |> json_response(403) + +      conn +      |> post("/inbox", non_create_data) +      |> json_response(403) + +      Config.put([:instance, :federating], true) + +      ret_conn = post(conn, "/inbox", data) +      assert "ok" == json_response(ret_conn, 200) + +      conn +      |> post("/inbox", non_create_data) +      |> json_response(400) +    end    end    describe "/users/:nickname/inbox" do @@ -517,22 +614,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do      test "it rejects reads from other users", %{conn: conn} do        user = insert(:user) -      otheruser = insert(:user) - -      conn = -        conn -        |> assign(:user, otheruser) -        |> put_req_header("accept", "application/activity+json") -        |> get("/users/#{user.nickname}/inbox") - -      assert json_response(conn, 403) -    end - -    test "it doesn't crash without an authenticated user", %{conn: conn} do -      user = insert(:user) +      other_user = insert(:user)        conn =          conn +        |> assign(:user, other_user)          |> put_req_header("accept", "application/activity+json")          |> get("/users/#{user.nickname}/inbox") @@ -613,14 +699,30 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do        refute recipient.follower_address in activity.data["cc"]        refute recipient.follower_address in activity.data["to"]      end + +    test "it requires authentication", %{conn: conn} do +      user = insert(:user) +      conn = put_req_header(conn, "accept", "application/activity+json") + +      ret_conn = get(conn, "/users/#{user.nickname}/inbox") +      assert json_response(ret_conn, 403) + +      ret_conn = +        conn +        |> assign(:user, user) +        |> get("/users/#{user.nickname}/inbox") + +      assert json_response(ret_conn, 200) +    end    end -  describe "/users/:nickname/outbox" do -    test "it will not bomb when there is no activity", %{conn: conn} do +  describe "GET /users/:nickname/outbox" do +    test "it returns 200 even if there're no activities", %{conn: conn} do        user = insert(:user)        conn =          conn +        |> assign(:user, user)          |> put_req_header("accept", "application/activity+json")          |> get("/users/#{user.nickname}/outbox") @@ -635,6 +737,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do        conn =          conn +        |> assign(:user, user)          |> put_req_header("accept", "application/activity+json")          |> get("/users/#{user.nickname}/outbox?page=true") @@ -647,24 +750,38 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do        conn =          conn +        |> assign(:user, user)          |> put_req_header("accept", "application/activity+json")          |> get("/users/#{user.nickname}/outbox?page=true")        assert response(conn, 200) =~ announce_activity.data["object"]      end -    test "it rejects posts from other users", %{conn: conn} do +    test "it requires authentication if instance is NOT federating", %{ +      conn: conn +    } do +      user = insert(:user) +      conn = put_req_header(conn, "accept", "application/activity+json") + +      ensure_federating_or_authenticated(conn, "/users/#{user.nickname}/outbox", user) +    end +  end + +  describe "POST /users/:nickname/outbox" do +    test "it rejects posts from other users / unauuthenticated users", %{conn: conn} do        data = File.read!("test/fixtures/activitypub-client-post-activity.json") |> Poison.decode!()        user = insert(:user) -      otheruser = insert(:user) +      other_user = insert(:user) +      conn = put_req_header(conn, "content-type", "application/activity+json") -      conn = -        conn -        |> assign(:user, otheruser) -        |> put_req_header("content-type", "application/activity+json") -        |> post("/users/#{user.nickname}/outbox", data) +      conn +      |> post("/users/#{user.nickname}/outbox", data) +      |> json_response(403) -      assert json_response(conn, 403) +      conn +      |> assign(:user, other_user) +      |> post("/users/#{user.nickname}/outbox", data) +      |> json_response(403)      end      test "it inserts an incoming create activity into the database", %{conn: conn} do @@ -779,24 +896,42 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do        result =          conn -        |> assign(:relay, true)          |> get("/relay/followers")          |> json_response(200)        assert result["first"]["orderedItems"] == [user.ap_id]      end + +    test "on non-federating instance, it returns 404", %{conn: conn} do +      Config.put([:instance, :federating], false) +      user = insert(:user) + +      conn +      |> assign(:user, user) +      |> get("/relay/followers") +      |> json_response(404) +    end    end    describe "/relay/following" do      test "it returns relay following", %{conn: conn} do        result =          conn -        |> assign(:relay, true)          |> get("/relay/following")          |> json_response(200)        assert result["first"]["orderedItems"] == []      end + +    test "on non-federating instance, it returns 404", %{conn: conn} do +      Config.put([:instance, :federating], false) +      user = insert(:user) + +      conn +      |> assign(:user, user) +      |> get("/relay/following") +      |> json_response(404) +    end    end    describe "/users/:nickname/followers" do @@ -807,32 +942,36 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do        result =          conn +        |> assign(:user, user_two)          |> get("/users/#{user_two.nickname}/followers")          |> json_response(200)        assert result["first"]["orderedItems"] == [user.ap_id]      end -    test "it returns returns a uri if the user has 'hide_followers' set", %{conn: conn} do +    test "it returns a uri if the user has 'hide_followers' set", %{conn: conn} do        user = insert(:user)        user_two = insert(:user, hide_followers: true)        User.follow(user, user_two)        result =          conn +        |> assign(:user, user)          |> get("/users/#{user_two.nickname}/followers")          |> json_response(200)        assert is_binary(result["first"])      end -    test "it returns a 403 error on pages, if the user has 'hide_followers' set and the request is not authenticated", +    test "it returns a 403 error on pages, if the user has 'hide_followers' set and the request is from another user",           %{conn: conn} do -      user = insert(:user, hide_followers: true) +      user = insert(:user) +      other_user = insert(:user, hide_followers: true)        result =          conn -        |> get("/users/#{user.nickname}/followers?page=1") +        |> assign(:user, user) +        |> get("/users/#{other_user.nickname}/followers?page=1")        assert result.status == 403        assert result.resp_body == "" @@ -864,6 +1003,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do        result =          conn +        |> assign(:user, user)          |> get("/users/#{user.nickname}/followers")          |> json_response(200) @@ -873,12 +1013,21 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do        result =          conn +        |> assign(:user, user)          |> get("/users/#{user.nickname}/followers?page=2")          |> json_response(200)        assert length(result["orderedItems"]) == 5        assert result["totalItems"] == 15      end + +    test "returns 403 if requester is not logged in", %{conn: conn} do +      user = insert(:user) + +      conn +      |> get("/users/#{user.nickname}/followers") +      |> json_response(403) +    end    end    describe "/users/:nickname/following" do @@ -889,6 +1038,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do        result =          conn +        |> assign(:user, user)          |> get("/users/#{user.nickname}/following")          |> json_response(200) @@ -896,25 +1046,28 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do      end      test "it returns a uri if the user has 'hide_follows' set", %{conn: conn} do -      user = insert(:user, hide_follows: true) -      user_two = insert(:user) +      user = insert(:user) +      user_two = insert(:user, hide_follows: true)        User.follow(user, user_two)        result =          conn -        |> get("/users/#{user.nickname}/following") +        |> assign(:user, user) +        |> get("/users/#{user_two.nickname}/following")          |> json_response(200)        assert is_binary(result["first"])      end -    test "it returns a 403 error on pages, if the user has 'hide_follows' set and the request is not authenticated", +    test "it returns a 403 error on pages, if the user has 'hide_follows' set and the request is from another user",           %{conn: conn} do -      user = insert(:user, hide_follows: true) +      user = insert(:user) +      user_two = insert(:user, hide_follows: true)        result =          conn -        |> get("/users/#{user.nickname}/following?page=1") +        |> assign(:user, user) +        |> get("/users/#{user_two.nickname}/following?page=1")        assert result.status == 403        assert result.resp_body == "" @@ -947,6 +1100,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do        result =          conn +        |> assign(:user, user)          |> get("/users/#{user.nickname}/following")          |> json_response(200) @@ -956,12 +1110,21 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do        result =          conn +        |> assign(:user, user)          |> get("/users/#{user.nickname}/following?page=2")          |> json_response(200)        assert length(result["orderedItems"]) == 5        assert result["totalItems"] == 15      end + +    test "returns 403 if requester is not logged in", %{conn: conn} do +      user = insert(:user) + +      conn +      |> get("/users/#{user.nickname}/following") +      |> json_response(403) +    end    end    describe "delivery tracking" do @@ -1046,8 +1209,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do      end    end -  describe "Additionnal ActivityPub C2S endpoints" do -    test "/api/ap/whoami", %{conn: conn} do +  describe "Additional ActivityPub C2S endpoints" do +    test "GET /api/ap/whoami", %{conn: conn} do        user = insert(:user)        conn = @@ -1058,12 +1221,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do        user = User.get_cached_by_id(user.id)        assert UserView.render("user.json", %{user: user}) == json_response(conn, 200) + +      conn +      |> get("/api/ap/whoami") +      |> json_response(403)      end      clear_config([:media_proxy])      clear_config([Pleroma.Upload]) -    test "uploadMedia", %{conn: conn} do +    test "POST /api/ap/upload_media", %{conn: conn} do        user = insert(:user)        desc = "Description of the image" @@ -1083,6 +1250,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do        assert object["name"] == desc        assert object["type"] == "Document"        assert object["actor"] == user.ap_id + +      conn +      |> post("/api/ap/upload_media", %{"file" => image, "description" => desc}) +      |> json_response(403)      end    end  end diff --git a/test/web/activity_pub/publisher_test.exs b/test/web/activity_pub/publisher_test.exs index 3404848d4..da26b13f7 100644 --- a/test/web/activity_pub/publisher_test.exs +++ b/test/web/activity_pub/publisher_test.exs @@ -23,6 +23,10 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do      :ok    end +  clear_config_all([:instance, :federating]) do +    Pleroma.Config.put([:instance, :federating], true) +  end +    describe "gather_webfinger_links/1" do      test "it returns links" do        user = insert(:user) diff --git a/test/web/feed/user_controller_test.exs b/test/web/feed/user_controller_test.exs index 19a019060..00c50f003 100644 --- a/test/web/feed/user_controller_test.exs +++ b/test/web/feed/user_controller_test.exs @@ -8,244 +8,130 @@ defmodule Pleroma.Web.Feed.UserControllerTest do    import Pleroma.Factory    import SweetXml +  alias Pleroma.Config    alias Pleroma.Object    alias Pleroma.User -  clear_config([:feed]) - -  test "gets a feed", %{conn: conn} do -    Pleroma.Config.put( -      [:feed, :post_title], -      %{max_length: 10, omission: "..."} -    ) - -    activity = insert(:note_activity) - -    note = -      insert(:note, -        data: %{ -          "content" => "This is :moominmamma: note ", -          "attachment" => [ -            %{ -              "url" => [%{"mediaType" => "image/png", "href" => "https://pleroma.gov/image.png"}] -            } -          ], -          "inReplyTo" => activity.data["id"] -        } -      ) - -    note_activity = insert(:note_activity, note: note) -    user = User.get_cached_by_ap_id(note_activity.data["actor"]) - -    note2 = -      insert(:note, -        user: user, -        data: %{"content" => "42 This is :moominmamma: note ", "inReplyTo" => activity.data["id"]} -      ) - -    _note_activity2 = insert(:note_activity, note: note2) -    object = Object.normalize(note_activity) - -    resp = -      conn -      |> put_req_header("content-type", "application/atom+xml") -      |> get(user_feed_path(conn, :feed, user.nickname)) -      |> response(200) - -    activity_titles = -      resp -      |> SweetXml.parse() -      |> SweetXml.xpath(~x"//entry/title/text()"l) - -    assert activity_titles == ['42 This...', 'This is...'] -    assert resp =~ object.data["content"] +  clear_config([:instance, :federating]) do +    Config.put([:instance, :federating], true)    end -  test "returns 404 for a missing feed", %{conn: conn} do -    conn = -      conn -      |> put_req_header("content-type", "application/atom+xml") -      |> get(user_feed_path(conn, :feed, "nonexisting")) +  describe "feed" do +    clear_config([:feed]) -    assert response(conn, 404) -  end +    test "gets a feed", %{conn: conn} do +      Config.put( +        [:feed, :post_title], +        %{max_length: 10, omission: "..."} +      ) -  describe "feed_redirect" do -    test "undefined format. it redirects to feed", %{conn: conn} do -      note_activity = insert(:note_activity) +      activity = insert(:note_activity) + +      note = +        insert(:note, +          data: %{ +            "content" => "This is :moominmamma: note ", +            "attachment" => [ +              %{ +                "url" => [ +                  %{"mediaType" => "image/png", "href" => "https://pleroma.gov/image.png"} +                ] +              } +            ], +            "inReplyTo" => activity.data["id"] +          } +        ) + +      note_activity = insert(:note_activity, note: note)        user = User.get_cached_by_ap_id(note_activity.data["actor"]) -      response = -        conn -        |> put_req_header("accept", "application/xml") -        |> get("/users/#{user.nickname}") -        |> response(302) +      note2 = +        insert(:note, +          user: user, +          data: %{ +            "content" => "42 This is :moominmamma: note ", +            "inReplyTo" => activity.data["id"] +          } +        ) -      assert response == -               "<html><body>You are being <a href=\"#{Pleroma.Web.base_url()}/users/#{ -                 user.nickname -               }/feed.atom\">redirected</a>.</body></html>" -    end +      _note_activity2 = insert(:note_activity, note: note2) +      object = Object.normalize(note_activity) -    test "undefined format. it returns error when user not found", %{conn: conn} do -      response = +      resp =          conn -        |> put_req_header("accept", "application/xml") -        |> get(user_feed_path(conn, :feed, "jimm")) -        |> response(404) - -      assert response == ~S({"error":"Not found"}) -    end +        |> put_req_header("content-type", "application/atom+xml") +        |> get(user_feed_path(conn, :feed, user.nickname)) +        |> response(200) -    test "activity+json format. it redirects on actual feed of user", %{conn: conn} do -      note_activity = insert(:note_activity) -      user = User.get_cached_by_ap_id(note_activity.data["actor"]) +      activity_titles = +        resp +        |> SweetXml.parse() +        |> SweetXml.xpath(~x"//entry/title/text()"l) -      response = -        conn -        |> put_req_header("accept", "application/activity+json") -        |> get("/users/#{user.nickname}") -        |> json_response(200) - -      assert response["endpoints"] == %{ -               "oauthAuthorizationEndpoint" => "#{Pleroma.Web.base_url()}/oauth/authorize", -               "oauthRegistrationEndpoint" => "#{Pleroma.Web.base_url()}/api/v1/apps", -               "oauthTokenEndpoint" => "#{Pleroma.Web.base_url()}/oauth/token", -               "sharedInbox" => "#{Pleroma.Web.base_url()}/inbox", -               "uploadMedia" => "#{Pleroma.Web.base_url()}/api/ap/upload_media" -             } - -      assert response["@context"] == [ -               "https://www.w3.org/ns/activitystreams", -               "http://localhost:4001/schemas/litepub-0.1.jsonld", -               %{"@language" => "und"} -             ] - -      assert Map.take(response, [ -               "followers", -               "following", -               "id", -               "inbox", -               "manuallyApprovesFollowers", -               "name", -               "outbox", -               "preferredUsername", -               "summary", -               "tag", -               "type", -               "url" -             ]) == %{ -               "followers" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/followers", -               "following" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/following", -               "id" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}", -               "inbox" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/inbox", -               "manuallyApprovesFollowers" => false, -               "name" => user.name, -               "outbox" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/outbox", -               "preferredUsername" => user.nickname, -               "summary" => user.bio, -               "tag" => [], -               "type" => "Person", -               "url" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}" -             } +      assert activity_titles == ['42 This...', 'This is...'] +      assert resp =~ object.data["content"]      end -    test "activity+json format. it returns error whe use not found", %{conn: conn} do -      response = +    test "returns 404 for a missing feed", %{conn: conn} do +      conn =          conn -        |> put_req_header("accept", "application/activity+json") -        |> get("/users/jimm") -        |> json_response(404) +        |> put_req_header("content-type", "application/atom+xml") +        |> get(user_feed_path(conn, :feed, "nonexisting")) -      assert response == "Not found" +      assert response(conn, 404)      end +  end -    test "json format. it redirects on actual feed of user", %{conn: conn} do +  # Note: see ActivityPubControllerTest for JSON format tests +  describe "feed_redirect" do +    test "with html format, it redirects to user feed", %{conn: conn} do        note_activity = insert(:note_activity)        user = User.get_cached_by_ap_id(note_activity.data["actor"])        response =          conn -        |> put_req_header("accept", "application/json")          |> get("/users/#{user.nickname}") -        |> json_response(200) - -      assert response["endpoints"] == %{ -               "oauthAuthorizationEndpoint" => "#{Pleroma.Web.base_url()}/oauth/authorize", -               "oauthRegistrationEndpoint" => "#{Pleroma.Web.base_url()}/api/v1/apps", -               "oauthTokenEndpoint" => "#{Pleroma.Web.base_url()}/oauth/token", -               "sharedInbox" => "#{Pleroma.Web.base_url()}/inbox", -               "uploadMedia" => "#{Pleroma.Web.base_url()}/api/ap/upload_media" -             } - -      assert response["@context"] == [ -               "https://www.w3.org/ns/activitystreams", -               "http://localhost:4001/schemas/litepub-0.1.jsonld", -               %{"@language" => "und"} -             ] - -      assert Map.take(response, [ -               "followers", -               "following", -               "id", -               "inbox", -               "manuallyApprovesFollowers", -               "name", -               "outbox", -               "preferredUsername", -               "summary", -               "tag", -               "type", -               "url" -             ]) == %{ -               "followers" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/followers", -               "following" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/following", -               "id" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}", -               "inbox" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/inbox", -               "manuallyApprovesFollowers" => false, -               "name" => user.name, -               "outbox" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/outbox", -               "preferredUsername" => user.nickname, -               "summary" => user.bio, -               "tag" => [], -               "type" => "Person", -               "url" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}" -             } +        |> response(200) + +      assert response == +               Fallback.RedirectController.redirector_with_meta( +                 conn, +                 %{user: user} +               ).resp_body      end -    test "json format. it returns error whe use not found", %{conn: conn} do +    test "with html format, it returns error when user is not found", %{conn: conn} do        response =          conn -        |> put_req_header("accept", "application/json")          |> get("/users/jimm")          |> json_response(404) -      assert response == "Not found" +      assert response == %{"error" => "Not found"}      end -    test "html format. it redirects on actual feed of user", %{conn: conn} do +    test "with non-html / non-json format, it redirects to user feed in atom format", %{ +      conn: conn +    } do        note_activity = insert(:note_activity)        user = User.get_cached_by_ap_id(note_activity.data["actor"]) -      response = +      conn =          conn +        |> put_req_header("accept", "application/xml")          |> get("/users/#{user.nickname}") -        |> response(200) -      assert response == -               Fallback.RedirectController.redirector_with_meta( -                 conn, -                 %{user: user} -               ).resp_body +      assert conn.status == 302 +      assert redirected_to(conn) == "#{Pleroma.Web.base_url()}/users/#{user.nickname}/feed.atom"      end -    test "html format. it returns error when user not found", %{conn: conn} do +    test "with non-html / non-json format, it returns error when user is not found", %{conn: conn} do        response =          conn -        |> get("/users/jimm") -        |> json_response(404) +        |> put_req_header("accept", "application/xml") +        |> get(user_feed_path(conn, :feed, "jimm")) +        |> response(404) -      assert response == %{"error" => "Not found"} +      assert response == ~S({"error":"Not found"})      end    end  end diff --git a/test/web/media_proxy/media_proxy_controller_test.exs b/test/web/media_proxy/media_proxy_controller_test.exs index f035dfeee..7ac7e4af1 100644 --- a/test/web/media_proxy/media_proxy_controller_test.exs +++ b/test/web/media_proxy/media_proxy_controller_test.exs @@ -52,9 +52,8 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do      url = Pleroma.Web.MediaProxy.encode_url("https://google.fn/test.png")      invalid_url = String.replace(url, "test.png", "test-file.png")      response = get(conn, invalid_url) -    html = "<html><body>You are being <a href=\"#{url}\">redirected</a>.</body></html>"      assert response.status == 302 -    assert response.resp_body == html +    assert redirected_to(response) == url    end    test "it performs ReverseProxy.call when signature valid", %{conn: conn} do diff --git a/test/web/ostatus/ostatus_controller_test.exs b/test/web/ostatus/ostatus_controller_test.exs index 2051841c2..3b84358e4 100644 --- a/test/web/ostatus/ostatus_controller_test.exs +++ b/test/web/ostatus/ostatus_controller_test.exs @@ -7,6 +7,7 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do    import Pleroma.Factory +  alias Pleroma.Config    alias Pleroma.Object    alias Pleroma.User    alias Pleroma.Web.CommonAPI @@ -16,22 +17,24 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do      :ok    end -  clear_config_all([:instance, :federating]) do -    Pleroma.Config.put([:instance, :federating], true) +  clear_config([:instance, :federating]) do +    Config.put([:instance, :federating], true)    end -  describe "GET object/2" do +  # Note: see ActivityPubControllerTest for JSON format tests +  describe "GET /objects/:uuid (text/html)" do +    setup %{conn: conn} do +      conn = put_req_header(conn, "accept", "text/html") +      %{conn: conn} +    end +      test "redirects to /notice/id for html format", %{conn: conn} do        note_activity = insert(:note_activity)        object = Object.normalize(note_activity)        [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, object.data["id"]))        url = "/objects/#{uuid}" -      conn = -        conn -        |> put_req_header("accept", "text/html") -        |> get(url) - +      conn = get(conn, url)        assert redirected_to(conn) == "/notice/#{note_activity.id}"      end @@ -45,23 +48,25 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do        |> response(404)      end -    test "404s on nonexisting objects", %{conn: conn} do +    test "404s on non-existing objects", %{conn: conn} do        conn        |> get("/objects/123")        |> response(404)      end    end -  describe "GET activity/2" do +  # Note: see ActivityPubControllerTest for JSON format tests +  describe "GET /activities/:uuid (text/html)" do +    setup %{conn: conn} do +      conn = put_req_header(conn, "accept", "text/html") +      %{conn: conn} +    end +      test "redirects to /notice/id for html format", %{conn: conn} do        note_activity = insert(:note_activity)        [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"])) -      conn = -        conn -        |> put_req_header("accept", "text/html") -        |> get("/activities/#{uuid}") - +      conn = get(conn, "/activities/#{uuid}")        assert redirected_to(conn) == "/notice/#{note_activity.id}"      end @@ -79,19 +84,6 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do        |> get("/activities/123")        |> response(404)      end - -    test "gets an activity in AS2 format", %{conn: conn} do -      note_activity = insert(:note_activity) -      [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"])) -      url = "/activities/#{uuid}" - -      conn = -        conn -        |> put_req_header("accept", "application/activity+json") -        |> get(url) - -      assert json_response(conn, 200) -    end    end    describe "GET notice/2" do @@ -170,7 +162,7 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do        assert response(conn, 404)      end -    test "404s a nonexisting notice", %{conn: conn} do +    test "404s a non-existing notice", %{conn: conn} do        url = "/notice/123"        conn = @@ -179,10 +171,21 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do        assert response(conn, 404)      end + +    test "it requires authentication if instance is NOT federating", %{ +      conn: conn +    } do +      user = insert(:user) +      note_activity = insert(:note_activity) + +      conn = put_req_header(conn, "accept", "text/html") + +      ensure_federating_or_authenticated(conn, "/notice/#{note_activity.id}", user) +    end    end    describe "GET /notice/:id/embed_player" do -    test "render embed player", %{conn: conn} do +    setup do        note_activity = insert(:note_activity)        object = Pleroma.Object.normalize(note_activity) @@ -204,9 +207,11 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do        |> Ecto.Changeset.change(data: object_data)        |> Pleroma.Repo.update() -      conn = -        conn -        |> get("/notice/#{note_activity.id}/embed_player") +      %{note_activity: note_activity} +    end + +    test "renders embed player", %{conn: conn, note_activity: note_activity} do +      conn = get(conn, "/notice/#{note_activity.id}/embed_player")        assert Plug.Conn.get_resp_header(conn, "x-frame-options") == ["ALLOW"] @@ -272,9 +277,19 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do        |> Ecto.Changeset.change(data: object_data)        |> Pleroma.Repo.update() -      assert conn -             |> get("/notice/#{note_activity.id}/embed_player") -             |> response(404) +      conn +      |> get("/notice/#{note_activity.id}/embed_player") +      |> response(404) +    end + +    test "it requires authentication if instance is NOT federating", %{ +      conn: conn, +      note_activity: note_activity +    } do +      user = insert(:user) +      conn = put_req_header(conn, "accept", "text/html") + +      ensure_federating_or_authenticated(conn, "/notice/#{note_activity.id}/embed_player", user)      end    end  end diff --git a/test/web/static_fe/static_fe_controller_test.exs b/test/web/static_fe/static_fe_controller_test.exs index 2ce8f9fa3..a072cc78f 100644 --- a/test/web/static_fe/static_fe_controller_test.exs +++ b/test/web/static_fe/static_fe_controller_test.exs @@ -1,56 +1,46 @@  defmodule Pleroma.Web.StaticFE.StaticFEControllerTest do    use Pleroma.Web.ConnCase +    alias Pleroma.Activity +  alias Pleroma.Config    alias Pleroma.Web.ActivityPub.Transmogrifier    alias Pleroma.Web.CommonAPI    import Pleroma.Factory    clear_config_all([:static_fe, :enabled]) do -    Pleroma.Config.put([:static_fe, :enabled], true) +    Config.put([:static_fe, :enabled], true)    end -  describe "user profile page" do -    test "just the profile as HTML", %{conn: conn} do -      user = insert(:user) - -      conn = -        conn -        |> put_req_header("accept", "text/html") -        |> get("/users/#{user.nickname}") +  clear_config([:instance, :federating]) do +    Config.put([:instance, :federating], true) +  end -      assert html_response(conn, 200) =~ user.nickname -    end +  setup %{conn: conn} do +    conn = put_req_header(conn, "accept", "text/html") +    user = insert(:user) -    test "renders json unless there's an html accept header", %{conn: conn} do -      user = insert(:user) +    %{conn: conn, user: user} +  end -      conn = -        conn -        |> put_req_header("accept", "application/json") -        |> get("/users/#{user.nickname}") +  describe "user profile html" do +    test "just the profile as HTML", %{conn: conn, user: user} do +      conn = get(conn, "/users/#{user.nickname}") -      assert json_response(conn, 200) +      assert html_response(conn, 200) =~ user.nickname      end      test "404 when user not found", %{conn: conn} do -      conn = -        conn -        |> put_req_header("accept", "text/html") -        |> get("/users/limpopo") +      conn = get(conn, "/users/limpopo")        assert html_response(conn, 404) =~ "not found"      end -    test "profile does not include private messages", %{conn: conn} do -      user = insert(:user) +    test "profile does not include private messages", %{conn: conn, user: user} do        CommonAPI.post(user, %{"status" => "public"})        CommonAPI.post(user, %{"status" => "private", "visibility" => "private"}) -      conn = -        conn -        |> put_req_header("accept", "text/html") -        |> get("/users/#{user.nickname}") +      conn = get(conn, "/users/#{user.nickname}")        html = html_response(conn, 200) @@ -58,14 +48,10 @@ defmodule Pleroma.Web.StaticFE.StaticFEControllerTest do        refute html =~ ">private<"      end -    test "pagination", %{conn: conn} do -      user = insert(:user) +    test "pagination", %{conn: conn, user: user} do        Enum.map(1..30, fn i -> CommonAPI.post(user, %{"status" => "test#{i}"}) end) -      conn = -        conn -        |> put_req_header("accept", "text/html") -        |> get("/users/#{user.nickname}") +      conn = get(conn, "/users/#{user.nickname}")        html = html_response(conn, 200) @@ -75,15 +61,11 @@ defmodule Pleroma.Web.StaticFE.StaticFEControllerTest do        refute html =~ ">test1<"      end -    test "pagination, page 2", %{conn: conn} do -      user = insert(:user) +    test "pagination, page 2", %{conn: conn, user: user} do        activities = Enum.map(1..30, fn i -> CommonAPI.post(user, %{"status" => "test#{i}"}) end)        {:ok, a11} = Enum.at(activities, 11) -      conn = -        conn -        |> put_req_header("accept", "text/html") -        |> get("/users/#{user.nickname}?max_id=#{a11.id}") +      conn = get(conn, "/users/#{user.nickname}?max_id=#{a11.id}")        html = html_response(conn, 200) @@ -92,17 +74,17 @@ defmodule Pleroma.Web.StaticFE.StaticFEControllerTest do        refute html =~ ">test20<"        refute html =~ ">test29<"      end + +    test "it requires authentication if instance is NOT federating", %{conn: conn, user: user} do +      ensure_federating_or_authenticated(conn, "/users/#{user.nickname}", user) +    end    end -  describe "notice rendering" do -    test "single notice page", %{conn: conn} do -      user = insert(:user) +  describe "notice html" do +    test "single notice page", %{conn: conn, user: user} do        {:ok, activity} = CommonAPI.post(user, %{"status" => "testing a thing!"}) -      conn = -        conn -        |> put_req_header("accept", "text/html") -        |> get("/notice/#{activity.id}") +      conn = get(conn, "/notice/#{activity.id}")        html = html_response(conn, 200)        assert html =~ "<header>" @@ -110,8 +92,7 @@ defmodule Pleroma.Web.StaticFE.StaticFEControllerTest do        assert html =~ "testing a thing!"      end -    test "shows the whole thread", %{conn: conn} do -      user = insert(:user) +    test "shows the whole thread", %{conn: conn, user: user} do        {:ok, activity} = CommonAPI.post(user, %{"status" => "space: the final frontier"})        CommonAPI.post(user, %{ @@ -119,70 +100,47 @@ defmodule Pleroma.Web.StaticFE.StaticFEControllerTest do          "in_reply_to_status_id" => activity.id        }) -      conn = -        conn -        |> put_req_header("accept", "text/html") -        |> get("/notice/#{activity.id}") +      conn = get(conn, "/notice/#{activity.id}")        html = html_response(conn, 200)        assert html =~ "the final frontier"        assert html =~ "voyages"      end -    test "redirect by AP object ID", %{conn: conn} do -      user = insert(:user) - +    test "redirect by AP object ID", %{conn: conn, user: user} do        {:ok, %Activity{data: %{"object" => object_url}}} =          CommonAPI.post(user, %{"status" => "beam me up"}) -      conn = -        conn -        |> put_req_header("accept", "text/html") -        |> get(URI.parse(object_url).path) +      conn = get(conn, URI.parse(object_url).path)        assert html_response(conn, 302) =~ "redirected"      end -    test "redirect by activity ID", %{conn: conn} do -      user = insert(:user) - +    test "redirect by activity ID", %{conn: conn, user: user} do        {:ok, %Activity{data: %{"id" => id}}} =          CommonAPI.post(user, %{"status" => "I'm a doctor, not a devops!"}) -      conn = -        conn -        |> put_req_header("accept", "text/html") -        |> get(URI.parse(id).path) +      conn = get(conn, URI.parse(id).path)        assert html_response(conn, 302) =~ "redirected"      end      test "404 when notice not found", %{conn: conn} do -      conn = -        conn -        |> put_req_header("accept", "text/html") -        |> get("/notice/88c9c317") +      conn = get(conn, "/notice/88c9c317")        assert html_response(conn, 404) =~ "not found"      end -    test "404 for private status", %{conn: conn} do -      user = insert(:user) - +    test "404 for private status", %{conn: conn, user: user} do        {:ok, activity} =          CommonAPI.post(user, %{"status" => "don't show me!", "visibility" => "private"}) -      conn = -        conn -        |> put_req_header("accept", "text/html") -        |> get("/notice/#{activity.id}") +      conn = get(conn, "/notice/#{activity.id}")        assert html_response(conn, 404) =~ "not found"      end -    test "302 for remote cached status", %{conn: conn} do -      user = insert(:user) - +    test "302 for remote cached status", %{conn: conn, user: user} do        message = %{          "@context" => "https://www.w3.org/ns/activitystreams",          "to" => user.follower_address, @@ -199,12 +157,15 @@ defmodule Pleroma.Web.StaticFE.StaticFEControllerTest do        assert {:ok, activity} = Transmogrifier.handle_incoming(message) -      conn = -        conn -        |> put_req_header("accept", "text/html") -        |> get("/notice/#{activity.id}") +      conn = get(conn, "/notice/#{activity.id}")        assert html_response(conn, 302) =~ "redirected"      end + +    test "it requires authentication if instance is NOT federating", %{conn: conn, user: user} do +      {:ok, activity} = CommonAPI.post(user, %{"status" => "testing a thing!"}) + +      ensure_federating_or_authenticated(conn, "/notice/#{activity.id}", user) +    end    end  end diff --git a/test/web/twitter_api/remote_follow_controller_test.exs b/test/web/twitter_api/remote_follow_controller_test.exs index 80a42989d..73062f18f 100644 --- a/test/web/twitter_api/remote_follow_controller_test.exs +++ b/test/web/twitter_api/remote_follow_controller_test.exs @@ -5,8 +5,10 @@  defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do    use Pleroma.Web.ConnCase +  alias Pleroma.Config    alias Pleroma.User    alias Pleroma.Web.CommonAPI +    import ExUnit.CaptureLog    import Pleroma.Factory @@ -15,6 +17,10 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do      :ok    end +  clear_config_all([:instance, :federating]) do +    Config.put([:instance, :federating], true) +  end +    clear_config([:instance])    clear_config([:frontend_configurations, :pleroma_fe])    clear_config([:user, :deny_follow_blocked]) diff --git a/test/web/twitter_api/util_controller_test.exs b/test/web/twitter_api/util_controller_test.exs index d464ce215..9d757b5ef 100644 --- a/test/web/twitter_api/util_controller_test.exs +++ b/test/web/twitter_api/util_controller_test.exs @@ -6,6 +6,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do    use Pleroma.Web.ConnCase    use Oban.Testing, repo: Pleroma.Repo +  alias Pleroma.Config    alias Pleroma.Tests.ObanHelpers    alias Pleroma.User @@ -178,7 +179,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do    describe "GET /api/statusnet/config" do      test "it returns config in xml format", %{conn: conn} do -      instance = Pleroma.Config.get(:instance) +      instance = Config.get(:instance)        response =          conn @@ -195,12 +196,12 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do      end      test "it returns config in json format", %{conn: conn} do -      instance = Pleroma.Config.get(:instance) -      Pleroma.Config.put([:instance, :managed_config], true) -      Pleroma.Config.put([:instance, :registrations_open], false) -      Pleroma.Config.put([:instance, :invites_enabled], true) -      Pleroma.Config.put([:instance, :public], false) -      Pleroma.Config.put([:frontend_configurations, :pleroma_fe], %{theme: "asuka-hospital"}) +      instance = Config.get(:instance) +      Config.put([:instance, :managed_config], true) +      Config.put([:instance, :registrations_open], false) +      Config.put([:instance, :invites_enabled], true) +      Config.put([:instance, :public], false) +      Config.put([:frontend_configurations, :pleroma_fe], %{theme: "asuka-hospital"})        response =          conn @@ -234,7 +235,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do      end      test "returns the state of safe_dm_mentions flag", %{conn: conn} do -      Pleroma.Config.put([:instance, :safe_dm_mentions], true) +      Config.put([:instance, :safe_dm_mentions], true)        response =          conn @@ -243,7 +244,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do        assert response["site"]["safeDMMentionsEnabled"] == "1" -      Pleroma.Config.put([:instance, :safe_dm_mentions], false) +      Config.put([:instance, :safe_dm_mentions], false)        response =          conn @@ -254,8 +255,8 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do      end      test "it returns the managed config", %{conn: conn} do -      Pleroma.Config.put([:instance, :managed_config], false) -      Pleroma.Config.put([:frontend_configurations, :pleroma_fe], %{theme: "asuka-hospital"}) +      Config.put([:instance, :managed_config], false) +      Config.put([:frontend_configurations, :pleroma_fe], %{theme: "asuka-hospital"})        response =          conn @@ -264,7 +265,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do        refute response["site"]["pleromafe"] -      Pleroma.Config.put([:instance, :managed_config], true) +      Config.put([:instance, :managed_config], true)        response =          conn @@ -287,7 +288,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do          }        ] -      Pleroma.Config.put(:frontend_configurations, config) +      Config.put(:frontend_configurations, config)        response =          conn @@ -320,7 +321,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do      clear_config([:instance, :healthcheck])      test "returns 503 when healthcheck disabled", %{conn: conn} do -      Pleroma.Config.put([:instance, :healthcheck], false) +      Config.put([:instance, :healthcheck], false)        response =          conn @@ -331,7 +332,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do      end      test "returns 200 when healthcheck enabled and all ok", %{conn: conn} do -      Pleroma.Config.put([:instance, :healthcheck], true) +      Config.put([:instance, :healthcheck], true)        with_mock Pleroma.Healthcheck,          system_info: fn -> %Pleroma.Healthcheck{healthy: true} end do @@ -351,7 +352,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do      end      test "returns 503 when healthcheck enabled and health is false", %{conn: conn} do -      Pleroma.Config.put([:instance, :healthcheck], true) +      Config.put([:instance, :healthcheck], true)        with_mock Pleroma.Healthcheck,          system_info: fn -> %Pleroma.Healthcheck{healthy: false} end do @@ -426,6 +427,10 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do    end    describe "POST /main/ostatus - remote_subscribe/2" do +    clear_config([:instance, :federating]) do +      Config.put([:instance, :federating], true) +    end +      test "renders subscribe form", %{conn: conn} do        user = insert(:user)  | 
