diff options
Diffstat (limited to 'test')
| -rw-r--r-- | test/integration/mastodon_websocket_test.exs | 2 | ||||
| -rw-r--r-- | test/plugs/oauth_scopes_plug_test.exs | 122 | ||||
| -rw-r--r-- | test/support/factory.ex | 2 | ||||
| -rw-r--r-- | test/user_test.exs | 23 | ||||
| -rw-r--r-- | test/web/activity_pub/activity_pub_controller_test.exs | 83 | ||||
| -rw-r--r-- | test/web/activity_pub/activity_pub_test.exs | 75 | ||||
| -rw-r--r-- | test/web/admin_api/admin_api_controller_test.exs | 48 | ||||
| -rw-r--r-- | test/web/common_api/common_api_test.exs | 31 | ||||
| -rw-r--r-- | test/web/mastodon_api/mastodon_api_controller_test.exs | 139 | ||||
| -rw-r--r-- | test/web/mastodon_api/status_view_test.exs | 2 | ||||
| -rw-r--r-- | test/web/oauth/authorization_test.exs | 46 | ||||
| -rw-r--r-- | test/web/oauth/oauth_controller_test.exs | 95 | ||||
| -rw-r--r-- | test/web/oauth/token_test.exs | 12 | ||||
| -rw-r--r-- | test/web/twitter_api/twitter_api_controller_test.exs | 34 | ||||
| -rw-r--r-- | test/web/twitter_api/util_controller_test.exs | 19 | ||||
| -rw-r--r-- | test/web/views/error_view_test.exs | 9 | 
16 files changed, 670 insertions, 72 deletions
| diff --git a/test/integration/mastodon_websocket_test.exs b/test/integration/mastodon_websocket_test.exs index 2e385f5ad..0c513b6e7 100644 --- a/test/integration/mastodon_websocket_test.exs +++ b/test/integration/mastodon_websocket_test.exs @@ -80,7 +80,7 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do          Pleroma.Repo.insert(            OAuth.App.register_changeset(%OAuth.App{}, %{              client_name: "client", -            scopes: "scope", +            scopes: ["scope"],              redirect_uris: "url"            })          ) diff --git a/test/plugs/oauth_scopes_plug_test.exs b/test/plugs/oauth_scopes_plug_test.exs new file mode 100644 index 000000000..f328026df --- /dev/null +++ b/test/plugs/oauth_scopes_plug_test.exs @@ -0,0 +1,122 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Plugs.OAuthScopesPlugTest do +  use Pleroma.Web.ConnCase, async: true + +  alias Pleroma.Plugs.OAuthScopesPlug +  alias Pleroma.Repo + +  import Pleroma.Factory + +  test "proceeds with no op if `assigns[:token]` is nil", %{conn: conn} do +    conn = +      conn +      |> assign(:user, insert(:user)) +      |> OAuthScopesPlug.call(%{scopes: ["read"]}) + +    refute conn.halted +    assert conn.assigns[:user] +  end + +  test "proceeds with no op if `token.scopes` fulfill specified 'any of' conditions", %{ +    conn: conn +  } do +    token = insert(:oauth_token, scopes: ["read", "write"]) |> Repo.preload(:user) + +    conn = +      conn +      |> assign(:user, token.user) +      |> assign(:token, token) +      |> OAuthScopesPlug.call(%{scopes: ["read"]}) + +    refute conn.halted +    assert conn.assigns[:user] +  end + +  test "proceeds with no op if `token.scopes` fulfill specified 'all of' conditions", %{ +    conn: conn +  } do +    token = insert(:oauth_token, scopes: ["scope1", "scope2", "scope3"]) |> Repo.preload(:user) + +    conn = +      conn +      |> assign(:user, token.user) +      |> assign(:token, token) +      |> OAuthScopesPlug.call(%{scopes: ["scope2", "scope3"], op: :&}) + +    refute conn.halted +    assert conn.assigns[:user] +  end + +  test "proceeds with cleared `assigns[:user]` if `token.scopes` doesn't fulfill specified 'any of' conditions " <> +         "and `fallback: :proceed_unauthenticated` option is specified", +       %{conn: conn} do +    token = insert(:oauth_token, scopes: ["read", "write"]) |> Repo.preload(:user) + +    conn = +      conn +      |> assign(:user, token.user) +      |> assign(:token, token) +      |> OAuthScopesPlug.call(%{scopes: ["follow"], fallback: :proceed_unauthenticated}) + +    refute conn.halted +    refute conn.assigns[:user] +  end + +  test "proceeds with cleared `assigns[:user]` if `token.scopes` doesn't fulfill specified 'all of' conditions " <> +         "and `fallback: :proceed_unauthenticated` option is specified", +       %{conn: conn} do +    token = insert(:oauth_token, scopes: ["read", "write"]) |> Repo.preload(:user) + +    conn = +      conn +      |> assign(:user, token.user) +      |> assign(:token, token) +      |> OAuthScopesPlug.call(%{ +        scopes: ["read", "follow"], +        op: :&, +        fallback: :proceed_unauthenticated +      }) + +    refute conn.halted +    refute conn.assigns[:user] +  end + +  test "returns 403 and halts in case of no :fallback option and `token.scopes` not fulfilling specified 'any of' conditions", +       %{conn: conn} do +    token = insert(:oauth_token, scopes: ["read", "write"]) +    any_of_scopes = ["follow"] + +    conn = +      conn +      |> assign(:token, token) +      |> OAuthScopesPlug.call(%{scopes: any_of_scopes}) + +    assert conn.halted +    assert 403 == conn.status + +    expected_error = "Insufficient permissions: #{Enum.join(any_of_scopes, ", ")}." +    assert Jason.encode!(%{error: expected_error}) == conn.resp_body +  end + +  test "returns 403 and halts in case of no :fallback option and `token.scopes` not fulfilling specified 'all of' conditions", +       %{conn: conn} do +    token = insert(:oauth_token, scopes: ["read", "write"]) +    all_of_scopes = ["write", "follow"] + +    conn = +      conn +      |> assign(:token, token) +      |> OAuthScopesPlug.call(%{scopes: all_of_scopes, op: :&}) + +    assert conn.halted +    assert 403 == conn.status + +    expected_error = +      "Insufficient permissions: #{Enum.join(all_of_scopes -- token.scopes, ", ")}." + +    assert Jason.encode!(%{error: expected_error}) == conn.resp_body +  end +end diff --git a/test/support/factory.ex b/test/support/factory.ex index 7a91549f5..d1956d1cd 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -214,7 +214,7 @@ defmodule Pleroma.Factory do      %Pleroma.Web.OAuth.App{        client_name: "Some client",        redirect_uris: "https://example.com/callback", -      scopes: "read", +      scopes: ["read", "write", "follow", "push"],        website: "https://example.com",        client_id: "aaabbb==",        client_secret: "aaa;/&bbb" diff --git a/test/user_test.exs b/test/user_test.exs index 92991d063..0b1c39ecf 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -594,6 +594,29 @@ defmodule Pleroma.UserTest do      end    end +  describe "mutes" do +    test "it mutes people" do +      user = insert(:user) +      muted_user = insert(:user) + +      refute User.mutes?(user, muted_user) + +      {:ok, user} = User.mute(user, muted_user) + +      assert User.mutes?(user, muted_user) +    end + +    test "it unmutes users" do +      user = insert(:user) +      muted_user = insert(:user) + +      {:ok, user} = User.mute(user, muted_user) +      {:ok, user} = User.unmute(user, muted_user) + +      refute User.mutes?(user, muted_user) +    end +  end +    describe "blocks" do      test "it blocks people" do        user = insert(:user) diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs index 398bedf77..6bd4493f5 100644 --- a/test/web/activity_pub/activity_pub_controller_test.exs +++ b/test/web/activity_pub/activity_pub_controller_test.exs @@ -41,7 +41,24 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do    end    describe "/users/:nickname" do -    test "it returns a json representation of the user", %{conn: conn} do +    test "it returns a json representation of the user with accept application/json", %{ +      conn: conn +    } do +      user = insert(:user) + +      conn = +        conn +        |> put_req_header("accept", "application/json") +        |> get("/users/#{user.nickname}") + +      user = Repo.get(User, user.id) + +      assert json_response(conn, 200) == UserView.render("user.json", %{user: user}) +    end + +    test "it returns a json representation of the user with accept application/activity+json", %{ +      conn: conn +    } do        user = insert(:user)        conn = @@ -53,10 +70,43 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do        assert json_response(conn, 200) == UserView.render("user.json", %{user: user})      end + +    test "it returns a json representation of the user with accept application/ld+json", %{ +      conn: conn +    } do +      user = insert(:user) + +      conn = +        conn +        |> put_req_header( +          "accept", +          "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"" +        ) +        |> get("/users/#{user.nickname}") + +      user = Repo.get(User, user.id) + +      assert json_response(conn, 200) == UserView.render("user.json", %{user: user}) +    end    end    describe "/object/:uuid" do -    test "it returns a json representation of the object", %{conn: conn} do +    test "it returns a json representation of the object with accept application/json", %{ +      conn: conn +    } do +      note = insert(:note) +      uuid = String.split(note.data["id"], "/") |> List.last() + +      conn = +        conn +        |> put_req_header("accept", "application/json") +        |> get("/objects/#{uuid}") + +      assert json_response(conn, 200) == ObjectView.render("object.json", %{object: note}) +    end + +    test "it returns a json representation of the object with accept application/activity+json", +         %{conn: conn} do        note = insert(:note)        uuid = String.split(note.data["id"], "/") |> List.last() @@ -68,6 +118,23 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do        assert json_response(conn, 200) == ObjectView.render("object.json", %{object: note})      end +    test "it returns a json representation of the object with accept application/ld+json", %{ +      conn: conn +    } do +      note = insert(:note) +      uuid = String.split(note.data["id"], "/") |> List.last() + +      conn = +        conn +        |> put_req_header( +          "accept", +          "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"" +        ) +        |> get("/objects/#{uuid}") + +      assert json_response(conn, 200) == ObjectView.render("object.json", %{object: note}) +    end +      test "it returns 404 for non-public messages", %{conn: conn} do        note = insert(:direct_note)        uuid = String.split(note.data["id"], "/") |> List.last() @@ -237,6 +304,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do    end    describe "/users/:nickname/outbox" do +    test "it will not bomb when there is no activity", %{conn: conn} do +      user = insert(:user) + +      conn = +        conn +        |> put_req_header("accept", "application/activity+json") +        |> get("/users/#{user.nickname}/outbox") + +      result = json_response(conn, 200) +      assert user.ap_id <> "/outbox" == result["id"] +    end +      test "it returns a note activity in a collection", %{conn: conn} do        note_activity = insert(:note_activity)        user = User.get_cached_by_ap_id(note_activity.data["actor"]) diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index a6f8b822a..11262c523 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.ActivityPub.ActivityPubTest do @@ -277,6 +277,48 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      assert Enum.member?(activities, activity_one)    end +  test "doesn't return muted activities" do +    activity_one = insert(:note_activity) +    activity_two = insert(:note_activity) +    activity_three = insert(:note_activity) +    user = insert(:user) +    booster = insert(:user) +    {:ok, user} = User.mute(user, %User{ap_id: activity_one.data["actor"]}) + +    activities = ActivityPub.fetch_activities([], %{"muting_user" => user}) + +    assert Enum.member?(activities, activity_two) +    assert Enum.member?(activities, activity_three) +    refute Enum.member?(activities, activity_one) + +    {:ok, user} = User.unmute(user, %User{ap_id: activity_one.data["actor"]}) + +    activities = ActivityPub.fetch_activities([], %{"muting_user" => user}) + +    assert Enum.member?(activities, activity_two) +    assert Enum.member?(activities, activity_three) +    assert Enum.member?(activities, activity_one) + +    {:ok, user} = User.mute(user, %User{ap_id: activity_three.data["actor"]}) +    {:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster) +    %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id) +    activity_three = Repo.get(Activity, activity_three.id) + +    activities = ActivityPub.fetch_activities([], %{"muting_user" => user}) + +    assert Enum.member?(activities, activity_two) +    refute Enum.member?(activities, activity_three) +    refute Enum.member?(activities, boost_activity) +    assert Enum.member?(activities, activity_one) + +    activities = ActivityPub.fetch_activities([], %{"muting_user" => nil}) + +    assert Enum.member?(activities, activity_two) +    assert Enum.member?(activities, activity_three) +    assert Enum.member?(activities, boost_activity) +    assert Enum.member?(activities, activity_one) +  end +    test "excludes reblogs on request" do      user = insert(:user)      {:ok, expected_activity} = ActivityBuilder.insert(%{"type" => "Create"}, %{:user => user}) @@ -700,6 +742,37 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      assert 3 = length(activities)    end +  test "it can create a Flag activity" do +    reporter = insert(:user) +    target_account = insert(:user) +    {:ok, activity} = CommonAPI.post(target_account, %{"status" => "foobar"}) +    context = Utils.generate_context_id() +    content = "foobar" + +    reporter_ap_id = reporter.ap_id +    target_ap_id = target_account.ap_id +    activity_ap_id = activity.data["id"] + +    assert {:ok, activity} = +             ActivityPub.flag(%{ +               actor: reporter, +               context: context, +               account: target_account, +               statuses: [activity], +               content: content +             }) + +    assert %Activity{ +             actor: ^reporter_ap_id, +             data: %{ +               "type" => "Flag", +               "content" => ^content, +               "context" => ^context, +               "object" => [^target_ap_id, ^activity_ap_id] +             } +           } = activity +  end +    describe "publish_one/1" do      test_with_mock "calls `Instances.set_reachable` on successful federation if `unreachable_since` is not specified",                     Instances, diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index a27c26f95..9fbaaba39 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -159,6 +159,54 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do      end    end +  describe "PUT /api/pleroma/admin/activation_status" do +    setup %{conn: conn} do +      admin = insert(:user, info: %{is_admin: true}) + +      conn = +        conn +        |> assign(:user, admin) +        |> put_req_header("accept", "application/json") + +      %{conn: conn} +    end + +    test "deactivates the user", %{conn: conn} do +      user = insert(:user) + +      conn = +        conn +        |> put("/api/pleroma/admin/activation_status/#{user.nickname}", %{status: false}) + +      user = Repo.get(User, user.id) +      assert user.info.deactivated == true +      assert json_response(conn, :no_content) +    end + +    test "activates the user", %{conn: conn} do +      user = insert(:user, info: %{deactivated: true}) + +      conn = +        conn +        |> put("/api/pleroma/admin/activation_status/#{user.nickname}", %{status: true}) + +      user = Repo.get(User, user.id) +      assert user.info.deactivated == false +      assert json_response(conn, :no_content) +    end + +    test "returns 403 when requested by a non-admin", %{conn: conn} do +      user = insert(:user) + +      conn = +        conn +        |> assign(:user, user) +        |> put("/api/pleroma/admin/activation_status/#{user.nickname}", %{status: false}) + +      assert json_response(conn, :forbidden) +    end +  end +    describe "POST /api/pleroma/admin/email_invite, with valid config" do      setup do        registrations_open = Pleroma.Config.get([:instance, :registrations_open]) diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs index 870648fb5..9ba320f59 100644 --- a/test/web/common_api/common_api_test.exs +++ b/test/web/common_api/common_api_test.exs @@ -190,4 +190,35 @@ defmodule Pleroma.Web.CommonAPITest do        {:error, _} = CommonAPI.add_mute(user, activity)      end    end + +  describe "reports" do +    test "creates a report" do +      reporter = insert(:user) +      target_user = insert(:user) + +      {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"}) + +      reporter_ap_id = reporter.ap_id +      target_ap_id = target_user.ap_id +      activity_ap_id = activity.data["id"] +      comment = "foobar" + +      report_data = %{ +        "account_id" => target_user.id, +        "comment" => comment, +        "status_ids" => [activity.id] +      } + +      assert {:ok, flag_activity} = CommonAPI.report(reporter, report_data) + +      assert %Activity{ +               actor: ^reporter_ap_id, +               data: %{ +                 "type" => "Flag", +                 "content" => ^comment, +                 "object" => [^target_ap_id, ^activity_ap_id] +               } +             } = flag_activity +    end +  end  end diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index e43bc4508..3dfbc8669 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -1206,6 +1206,42 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      assert id == to_string(other_user.id)    end +  test "muting / unmuting a user", %{conn: conn} do +    user = insert(:user) +    other_user = insert(:user) + +    conn = +      conn +      |> assign(:user, user) +      |> post("/api/v1/accounts/#{other_user.id}/mute") + +    assert %{"id" => _id, "muting" => true} = json_response(conn, 200) + +    user = Repo.get(User, user.id) + +    conn = +      build_conn() +      |> assign(:user, user) +      |> post("/api/v1/accounts/#{other_user.id}/unmute") + +    assert %{"id" => _id, "muting" => false} = json_response(conn, 200) +  end + +  test "getting a list of mutes", %{conn: conn} do +    user = insert(:user) +    other_user = insert(:user) + +    {:ok, user} = User.mute(user, other_user) + +    conn = +      conn +      |> assign(:user, user) +      |> get("/api/v1/mutes") + +    other_user_id = to_string(other_user.id) +    assert [%{"id" => ^other_user_id}] = json_response(conn, 200) +  end +    test "blocking / unblocking a user", %{conn: conn} do      user = insert(:user)      other_user = insert(:user) @@ -1282,26 +1318,10 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      assert "even.worse.site" in domain_blocks    end -  test "unimplemented mute endpoints" do +  test "unimplemented follow_requests, blocks, domain blocks" do      user = insert(:user) -    other_user = insert(:user) -    ["mute", "unmute"] -    |> Enum.each(fn endpoint -> -      conn = -        build_conn() -        |> assign(:user, user) -        |> post("/api/v1/accounts/#{other_user.id}/#{endpoint}") - -      assert %{"id" => id} = json_response(conn, 200) -      assert id == to_string(other_user.id) -    end) -  end - -  test "unimplemented mutes, follow_requests, blocks, domain blocks" do -    user = insert(:user) - -    ["blocks", "domain_blocks", "mutes", "follow_requests"] +    ["blocks", "domain_blocks", "follow_requests"]      |> Enum.each(fn endpoint ->        conn =          build_conn() @@ -1536,6 +1556,24 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        assert user_response = json_response(conn, 200)        assert user_response["header"] != User.banner_url(user)      end + +    test "requires 'write' permission", %{conn: conn} do +      token1 = insert(:oauth_token, scopes: ["read"]) +      token2 = insert(:oauth_token, scopes: ["write", "follow"]) + +      for token <- [token1, token2] do +        conn = +          conn +          |> put_req_header("authorization", "Bearer #{token.token}") +          |> patch("/api/v1/accounts/update_credentials", %{}) + +        if token == token1 do +          assert %{"error" => "Insufficient permissions: write."} == json_response(conn, 403) +        else +          assert json_response(conn, 200) +        end +      end +    end    end    test "get instance information", %{conn: conn} do @@ -1817,4 +1855,69 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do      assert json_response(set_flavour, 200) == json_response(get_new_flavour, 200)    end + +  describe "reports" do +    setup do +      reporter = insert(:user) +      target_user = insert(:user) + +      {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"}) + +      [reporter: reporter, target_user: target_user, activity: activity] +    end + +    test "submit a basic report", %{conn: conn, reporter: reporter, target_user: target_user} do +      assert %{"action_taken" => false, "id" => _} = +               conn +               |> assign(:user, reporter) +               |> post("/api/v1/reports", %{"account_id" => target_user.id}) +               |> json_response(200) +    end + +    test "submit a report with statuses and comment", %{ +      conn: conn, +      reporter: reporter, +      target_user: target_user, +      activity: activity +    } do +      assert %{"action_taken" => false, "id" => _} = +               conn +               |> assign(:user, reporter) +               |> post("/api/v1/reports", %{ +                 "account_id" => target_user.id, +                 "status_ids" => [activity.id], +                 "comment" => "bad status!" +               }) +               |> json_response(200) +    end + +    test "accound_id is required", %{ +      conn: conn, +      reporter: reporter, +      activity: activity +    } do +      assert %{"error" => "Valid `account_id` required"} = +               conn +               |> assign(:user, reporter) +               |> post("/api/v1/reports", %{"status_ids" => [activity.id]}) +               |> json_response(400) +    end + +    test "comment must be up to the size specified in the config", %{ +      conn: conn, +      reporter: reporter, +      target_user: target_user +    } do +      max_size = Pleroma.Config.get([:instance, :max_report_comment_size], 1000) +      comment = String.pad_trailing("a", max_size + 1, "a") + +      error = %{"error" => "Comment must be up to #{max_size} characters"} + +      assert ^error = +               conn +               |> assign(:user, reporter) +               |> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment}) +               |> json_response(400) +    end +  end  end diff --git a/test/web/mastodon_api/status_view_test.exs b/test/web/mastodon_api/status_view_test.exs index 0dc9c538c..3412a6be2 100644 --- a/test/web/mastodon_api/status_view_test.exs +++ b/test/web/mastodon_api/status_view_test.exs @@ -81,7 +81,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do      expected = %{        id: to_string(note.id),        uri: note.data["object"]["id"], -      url: note.data["object"]["id"], +      url: Pleroma.Web.Router.Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, note),        account: AccountView.render("account.json", %{user: user}),        in_reply_to_id: nil,        in_reply_to_account_id: nil, diff --git a/test/web/oauth/authorization_test.exs b/test/web/oauth/authorization_test.exs index 81618e935..306db2e62 100644 --- a/test/web/oauth/authorization_test.exs +++ b/test/web/oauth/authorization_test.exs @@ -8,36 +8,37 @@ defmodule Pleroma.Web.OAuth.AuthorizationTest do    alias Pleroma.Web.OAuth.App    import Pleroma.Factory -  test "create an authorization token for a valid app" do +  setup do      {:ok, app} =        Repo.insert(          App.register_changeset(%App{}, %{            client_name: "client", -          scopes: "scope", +          scopes: ["read", "write"],            redirect_uris: "url"          })        ) +    %{app: app} +  end + +  test "create an authorization token for a valid app", %{app: app} do      user = insert(:user) -    {:ok, auth} = Authorization.create_authorization(app, user) +    {:ok, auth1} = Authorization.create_authorization(app, user) +    assert auth1.scopes == app.scopes -    assert auth.user_id == user.id -    assert auth.app_id == app.id -    assert String.length(auth.token) > 10 -    assert auth.used == false -  end +    {:ok, auth2} = Authorization.create_authorization(app, user, ["read"]) +    assert auth2.scopes == ["read"] -  test "use up a token" do -    {:ok, app} = -      Repo.insert( -        App.register_changeset(%App{}, %{ -          client_name: "client", -          scopes: "scope", -          redirect_uris: "url" -        }) -      ) +    for auth <- [auth1, auth2] do +      assert auth.user_id == user.id +      assert auth.app_id == app.id +      assert String.length(auth.token) > 10 +      assert auth.used == false +    end +  end +  test "use up a token", %{app: app} do      user = insert(:user)      {:ok, auth} = Authorization.create_authorization(app, user) @@ -61,16 +62,7 @@ defmodule Pleroma.Web.OAuth.AuthorizationTest do      assert {:error, "token expired"} == Authorization.use_token(expired_auth)    end -  test "delete authorizations" do -    {:ok, app} = -      Repo.insert( -        App.register_changeset(%App{}, %{ -          client_name: "client", -          scopes: "scope", -          redirect_uris: "url" -        }) -      ) - +  test "delete authorizations", %{app: app} do      user = insert(:user)      {:ok, auth} = Authorization.create_authorization(app, user) diff --git a/test/web/oauth/oauth_controller_test.exs b/test/web/oauth/oauth_controller_test.exs index 2315f9a34..53d83e6e8 100644 --- a/test/web/oauth/oauth_controller_test.exs +++ b/test/web/oauth/oauth_controller_test.exs @@ -12,7 +12,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do    test "redirects with oauth authorization" do      user = insert(:user) -    app = insert(:oauth_app) +    app = insert(:oauth_app, scopes: ["read", "write", "follow"])      conn =        build_conn() @@ -22,6 +22,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do            "password" => "test",            "client_id" => app.client_id,            "redirect_uri" => app.redirect_uris, +          "scope" => "read write",            "state" => "statepassed"          }        }) @@ -32,10 +33,12 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do      query = URI.parse(target).query |> URI.query_decoder() |> Map.new()      assert %{"state" => "statepassed", "code" => code} = query -    assert Repo.get_by(Authorization, token: code) +    auth = Repo.get_by(Authorization, token: code) +    assert auth +    assert auth.scopes == ["read", "write"]    end -  test "correctly handles wrong credentials", %{conn: conn} do +  test "returns 401 for wrong credentials", %{conn: conn} do      user = insert(:user)      app = insert(:oauth_app) @@ -47,7 +50,8 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do            "password" => "wrong",            "client_id" => app.client_id,            "redirect_uri" => app.redirect_uris, -          "state" => "statepassed" +          "state" => "statepassed", +          "scope" => Enum.join(app.scopes, " ")          }        })        |> html_response(:unauthorized) @@ -57,14 +61,66 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do      assert result =~ app.redirect_uris      # Error message -    assert result =~ "Invalid" +    assert result =~ "Invalid Username/Password"    end -  test "issues a token for an all-body request" do +  test "returns 401 for missing scopes", %{conn: conn} do      user = insert(:user)      app = insert(:oauth_app) -    {:ok, auth} = Authorization.create_authorization(app, user) +    result = +      conn +      |> post("/oauth/authorize", %{ +        "authorization" => %{ +          "name" => user.nickname, +          "password" => "test", +          "client_id" => app.client_id, +          "redirect_uri" => app.redirect_uris, +          "state" => "statepassed", +          "scope" => "" +        } +      }) +      |> html_response(:unauthorized) + +    # Keep the details +    assert result =~ app.client_id +    assert result =~ app.redirect_uris + +    # Error message +    assert result =~ "Permissions not specified" +  end + +  test "returns 401 for scopes beyond app scopes", %{conn: conn} do +    user = insert(:user) +    app = insert(:oauth_app, scopes: ["read", "write"]) + +    result = +      conn +      |> post("/oauth/authorize", %{ +        "authorization" => %{ +          "name" => user.nickname, +          "password" => "test", +          "client_id" => app.client_id, +          "redirect_uri" => app.redirect_uris, +          "state" => "statepassed", +          "scope" => "read write follow" +        } +      }) +      |> html_response(:unauthorized) + +    # Keep the details +    assert result =~ app.client_id +    assert result =~ app.redirect_uris + +    # Error message +    assert result =~ "Permissions not specified" +  end + +  test "issues a token for an all-body request" do +    user = insert(:user) +    app = insert(:oauth_app, scopes: ["read", "write"]) + +    {:ok, auth} = Authorization.create_authorization(app, user, ["write"])      conn =        build_conn() @@ -77,15 +133,19 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do        })      assert %{"access_token" => token} = json_response(conn, 200) -    assert Repo.get_by(Token, token: token) + +    token = Repo.get_by(Token, token: token) +    assert token +    assert token.scopes == auth.scopes    end -  test "issues a token for `password` grant_type with valid credentials" do +  test "issues a token for `password` grant_type with valid credentials, with full permissions by default" do      password = "testpassword"      user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password)) -    app = insert(:oauth_app) +    app = insert(:oauth_app, scopes: ["read", "write"]) +    # Note: "scope" param is intentionally omitted      conn =        build_conn()        |> post("/oauth/token", %{ @@ -97,14 +157,18 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do        })      assert %{"access_token" => token} = json_response(conn, 200) -    assert Repo.get_by(Token, token: token) + +    token = Repo.get_by(Token, token: token) +    assert token +    assert token.scopes == app.scopes    end    test "issues a token for request with HTTP basic auth client credentials" do      user = insert(:user) -    app = insert(:oauth_app) +    app = insert(:oauth_app, scopes: ["scope1", "scope2"]) -    {:ok, auth} = Authorization.create_authorization(app, user) +    {:ok, auth} = Authorization.create_authorization(app, user, ["scope2"]) +    assert auth.scopes == ["scope2"]      app_encoded =        (URI.encode_www_form(app.client_id) <> ":" <> URI.encode_www_form(app.client_secret)) @@ -120,7 +184,10 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do        })      assert %{"access_token" => token} = json_response(conn, 200) -    assert Repo.get_by(Token, token: token) + +    token = Repo.get_by(Token, token: token) +    assert token +    assert token.scopes == ["scope2"]    end    test "rejects token exchange with invalid client credentials" do diff --git a/test/web/oauth/token_test.exs b/test/web/oauth/token_test.exs index 4dab4a308..62444a0fa 100644 --- a/test/web/oauth/token_test.exs +++ b/test/web/oauth/token_test.exs @@ -11,24 +11,26 @@ defmodule Pleroma.Web.OAuth.TokenTest do    import Pleroma.Factory -  test "exchanges a auth token for an access token" do +  test "exchanges a auth token for an access token, preserving `scopes`" do      {:ok, app} =        Repo.insert(          App.register_changeset(%App{}, %{            client_name: "client", -          scopes: "scope", +          scopes: ["read", "write"],            redirect_uris: "url"          })        )      user = insert(:user) -    {:ok, auth} = Authorization.create_authorization(app, user) +    {:ok, auth} = Authorization.create_authorization(app, user, ["read"]) +    assert auth.scopes == ["read"]      {:ok, token} = Token.exchange_token(app, auth)      assert token.app_id == app.id      assert token.user_id == user.id +    assert token.scopes == auth.scopes      assert String.length(token.token) > 10      assert String.length(token.refresh_token) > 10 @@ -41,7 +43,7 @@ defmodule Pleroma.Web.OAuth.TokenTest do        Repo.insert(          App.register_changeset(%App{}, %{            client_name: "client1", -          scopes: "scope", +          scopes: ["scope"],            redirect_uris: "url"          })        ) @@ -50,7 +52,7 @@ defmodule Pleroma.Web.OAuth.TokenTest do        Repo.insert(          App.register_changeset(%App{}, %{            client_name: "client2", -          scopes: "scope", +          scopes: ["scope"],            redirect_uris: "url"          })        ) diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs index 1571ab68e..05a832967 100644 --- a/test/web/twitter_api/twitter_api_controller_test.exs +++ b/test/web/twitter_api/twitter_api_controller_test.exs @@ -14,6 +14,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do    alias Pleroma.Notification    alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.Web.OAuth.Token +  alias Pleroma.Web.TwitterAPI.Controller    alias Pleroma.Web.TwitterAPI.UserView    alias Pleroma.Web.TwitterAPI.NotificationView    alias Pleroma.Web.CommonAPI @@ -22,6 +23,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do    alias Ecto.Changeset    import Pleroma.Factory +  import Mock    @banner "data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7" @@ -187,6 +189,20 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        |> get("/api/statuses/public_timeline.json")        |> json_response(200)      end + +    test_with_mock "treats user as unauthenticated if `assigns[:token]` is present but lacks `read` permission", +                   Controller, +                   [:passthrough], +                   [] do +      token = insert(:oauth_token, scopes: ["write"]) + +      build_conn() +      |> put_req_header("authorization", "Bearer #{token.token}") +      |> get("/api/statuses/public_timeline.json") +      |> json_response(200) + +      assert called(Controller.public_timeline(%{assigns: %{user: nil}}, :_)) +    end    end    describe "GET /statuses/public_and_external_timeline.json" do @@ -1690,6 +1706,24 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        assert [relationship] = json_response(conn, 200)        assert other_user.id == relationship["id"]      end + +    test "requires 'read' permission", %{conn: conn} do +      token1 = insert(:oauth_token, scopes: ["write"]) +      token2 = insert(:oauth_token, scopes: ["read"]) + +      for token <- [token1, token2] do +        conn = +          conn +          |> put_req_header("authorization", "Bearer #{token.token}") +          |> get("/api/pleroma/friend_requests") + +        if token == token1 do +          assert %{"error" => "Insufficient permissions: read."} == json_response(conn, 403) +        else +          assert json_response(conn, 200) +        end +      end +    end    end    describe "POST /api/pleroma/friendships/approve" do diff --git a/test/web/twitter_api/util_controller_test.exs b/test/web/twitter_api/util_controller_test.exs index 007d7d8e6..fc762ab18 100644 --- a/test/web/twitter_api/util_controller_test.exs +++ b/test/web/twitter_api/util_controller_test.exs @@ -16,6 +16,25 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do        assert response == "job started"      end + +    test "requires 'follow' permission", %{conn: conn} do +      token1 = insert(:oauth_token, scopes: ["read", "write"]) +      token2 = insert(:oauth_token, scopes: ["follow"]) +      another_user = insert(:user) + +      for token <- [token1, token2] do +        conn = +          conn +          |> put_req_header("authorization", "Bearer #{token.token}") +          |> post("/api/pleroma/follow_import", %{"list" => "#{another_user.ap_id}"}) + +        if token == token1 do +          assert %{"error" => "Insufficient permissions: follow."} == json_response(conn, 403) +        else +          assert json_response(conn, 200) +        end +      end +    end    end    describe "POST /api/pleroma/blocks_import" do diff --git a/test/web/views/error_view_test.exs b/test/web/views/error_view_test.exs index 16a0c8cef..d529fd2c3 100644 --- a/test/web/views/error_view_test.exs +++ b/test/web/views/error_view_test.exs @@ -14,11 +14,16 @@ defmodule Pleroma.Web.ErrorViewTest do    test "render 500.json" do      assert render(Pleroma.Web.ErrorView, "500.json", []) == -             %{errors: %{detail: "Internal server error"}} +             %{errors: %{detail: "Internal server error", reason: "nil"}}    end    test "render any other" do      assert render(Pleroma.Web.ErrorView, "505.json", []) == -             %{errors: %{detail: "Internal server error"}} +             %{errors: %{detail: "Internal server error", reason: "nil"}} +  end + +  test "render 500.json with reason" do +    assert render(Pleroma.Web.ErrorView, "500.json", reason: "test reason") == +             %{errors: %{detail: "Internal server error", reason: "\"test reason\""}}    end  end | 
