From 826fc446d56b48b67e97144c74bbf74109fb8168 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Tue, 4 Dec 2018 18:35:57 +0300 Subject: [PATCH 01/10] [#210] TwitterAPI: implemented /api/media/metadata/create to allow uploads description (alt text) setting. --- lib/pleroma/web/router.ex | 1 + .../web/twitter_api/twitter_api_controller.ex | 18 ++++++++++++++++- .../twitter_api_controller_test.exs | 20 +++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index d6a9d5779..b7c79d2eb 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -324,6 +324,7 @@ defmodule Pleroma.Web.Router do post("/statusnet/media/upload", TwitterAPI.Controller, :upload) post("/media/upload", TwitterAPI.Controller, :upload_json) + post("/media/metadata/create", TwitterAPI.Controller, :update_media) post("/favorites/create/:id", TwitterAPI.Controller, :favorite) post("/favorites/create", TwitterAPI.Controller, :favorite) diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index 961250d92..a9e45f91e 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -4,7 +4,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do alias Pleroma.Web.TwitterAPI.{TwitterAPI, UserView, ActivityView, NotificationView} alias Pleroma.Web.CommonAPI alias Pleroma.Web.CommonAPI.Utils, as: CommonUtils - alias Pleroma.{Repo, Activity, User, Notification} + alias Pleroma.{Repo, Activity, Object, User, Notification} alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Utils alias Ecto.Changeset @@ -226,6 +226,22 @@ def fetch_conversation(%{assigns: %{user: user}} = conn, %{"id" => id}) do end end + @doc "https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-metadata-create" + def update_media(%{assigns: %{user: _}} = conn, %{"media_id" => id} = data) do + description = get_in(data, ["alt_text", "text"]) || data["name"] || data["description"] + + with %Object{} = object <- Repo.get(Object, id), is_binary(description) do + new_data = Map.put(object.data, "name", description) + + change = Object.change(object, %{data: new_data}) + {:ok, _} = Repo.update(change) + end + + conn + |> put_status(:no_content) + |> json("") + end + def upload(conn, %{"media" => media}) do response = TwitterAPI.upload(media) diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs index a6495ffc1..8faa4b58e 100644 --- a/test/web/twitter_api/twitter_api_controller_test.exs +++ b/test/web/twitter_api/twitter_api_controller_test.exs @@ -1253,4 +1253,24 @@ test "it returns users, ordered by similarity", %{conn: conn} do assert [user.id, user_two.id, user_three.id] == Enum.map(resp, fn %{"id" => id} -> id end) end end + + describe "POST /api/media/metadata/create" do + test "it updates `data[name]` of referenced Object with provided value", %{conn: conn} do + user = insert(:user) + object = insert(:note) + description = "Informative description of the image. Initial: #{object.data["name"]}}" + + _conn = + conn + |> assign(:user, user) + |> post("/api/media/metadata/create.json", %{ + "media_id" => object.id, + "alt_text" => %{"text" => description} + }) + |> json_response(:no_content) + + object = Repo.get!(Object, object.id) + assert object.data["name"] == description + end + end end From 48e6193bf2c6a03068f1c6a96429fadffaa7794b Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Tue, 4 Dec 2018 19:24:41 +0300 Subject: [PATCH 02/10] [#210] Refactoring. --- lib/pleroma/web/twitter_api/twitter_api_controller.ex | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index a9e45f91e..c846dbd60 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -232,9 +232,7 @@ def update_media(%{assigns: %{user: _}} = conn, %{"media_id" => id} = data) do with %Object{} = object <- Repo.get(Object, id), is_binary(description) do new_data = Map.put(object.data, "name", description) - - change = Object.change(object, %{data: new_data}) - {:ok, _} = Repo.update(change) + {:ok, _} = object |> Object.change(%{data: new_data}) |> Repo.update() end conn From 44ab3dbe2c3d25a1772b99679653eaf96d4fbd8b Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Tue, 4 Dec 2018 19:45:09 +0300 Subject: [PATCH 03/10] [#210] Refactoring. --- .../twitter_api/twitter_api_controller_test.exs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs index 8faa4b58e..21e844124 100644 --- a/test/web/twitter_api/twitter_api_controller_test.exs +++ b/test/web/twitter_api/twitter_api_controller_test.exs @@ -1260,14 +1260,13 @@ test "it updates `data[name]` of referenced Object with provided value", %{conn: object = insert(:note) description = "Informative description of the image. Initial: #{object.data["name"]}}" - _conn = - conn - |> assign(:user, user) - |> post("/api/media/metadata/create.json", %{ - "media_id" => object.id, - "alt_text" => %{"text" => description} - }) - |> json_response(:no_content) + conn + |> assign(:user, user) + |> post("/api/media/metadata/create.json", %{ + "media_id" => object.id, + "alt_text" => %{"text" => description} + }) + |> json_response(:no_content) object = Repo.get!(Object, object.id) assert object.data["name"] == description From be187f82f798a904755fc754538d560cde901a88 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Wed, 5 Dec 2018 11:48:50 +0300 Subject: [PATCH 04/10] [#210] Further refactoring. --- .../web/twitter_api/twitter_api_controller.ex | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index c846dbd60..c9e845aea 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -226,13 +226,21 @@ def fetch_conversation(%{assigns: %{user: user}} = conn, %{"id" => id}) do end end - @doc "https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-metadata-create" + @doc """ + Updates metadata of uploaded media object. + Derived from [Twitter API endpoint](https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-metadata-create). + """ def update_media(%{assigns: %{user: _}} = conn, %{"media_id" => id} = data) do description = get_in(data, ["alt_text", "text"]) || data["name"] || data["description"] - with %Object{} = object <- Repo.get(Object, id), is_binary(description) do + with %Object{} = object <- Repo.get(Object, id), + is_binary(description) do new_data = Map.put(object.data, "name", description) - {:ok, _} = object |> Object.change(%{data: new_data}) |> Repo.update() + + {:ok, _} = + object + |> Object.change(%{data: new_data}) + |> Repo.update() end conn From 53797d19c5e8463388862eaa20931c8cb78d66a6 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Wed, 5 Dec 2018 11:56:31 +0300 Subject: [PATCH 05/10] [#210] Test update (replaced bang- with non-bang method). --- test/web/twitter_api/twitter_api_controller_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs index 21e844124..478763de7 100644 --- a/test/web/twitter_api/twitter_api_controller_test.exs +++ b/test/web/twitter_api/twitter_api_controller_test.exs @@ -1268,7 +1268,7 @@ test "it updates `data[name]` of referenced Object with provided value", %{conn: }) |> json_response(:no_content) - object = Repo.get!(Object, object.id) + object = Repo.get(Object, object.id) assert object.data["name"] == description end end From 848151f7cbf372d008c178d13c9a74942164c955 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Wed, 5 Dec 2018 13:37:06 +0300 Subject: [PATCH 06/10] [#210] [TwitterAPI] Made actor be stored for uploads. Added ownership check to `update_media` action. Added controller tests for `upload` and `update_media` actions. Refactoring. --- lib/pleroma/web/activity_pub/activity_pub.ex | 3 +- lib/pleroma/web/twitter_api/twitter_api.ex | 8 ++- .../web/twitter_api/twitter_api_controller.ex | 43 +++++++----- test/support/data_case.ex | 17 +++++ test/upload_test.exs | 17 +---- .../mastodon_api_controller_test.exs | 2 +- .../twitter_api_controller_test.exs | 67 +++++++++++++++++-- test/web/twitter_api/twitter_api_test.exs | 3 +- 8 files changed, 120 insertions(+), 40 deletions(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 7e207c620..39692163f 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -574,7 +574,8 @@ def fetch_activities_bounded(recipients_to, recipients_cc, opts \\ %{}) do def upload(file, opts \\ []) do with {:ok, data} <- Upload.store(file, opts) do - Repo.insert(%Object{data: data}) + obj_data = if opts[:actor], do: Map.put(data, "actor", opts[:actor]), else: data + Repo.insert(%Object{data: obj_data}) end end diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index c19a4f084..b9468ab03 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -93,8 +93,12 @@ def unfav(%User{} = user, ap_id_or_id) do end end - def upload(%Plug.Upload{} = file, format \\ "xml") do - {:ok, object} = ActivityPub.upload(file) + def ap_upload(%Plug.Upload{} = file, %User{} = user) do + ActivityPub.upload(file, actor: User.ap_id(user)) + end + + def upload(%Plug.Upload{} = file, %User{} = user, format \\ "xml") do + {:ok, object} = ap_upload(file, user) url = List.first(object.data["url"]) href = url["href"] diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index c9e845aea..2f12131e7 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -230,34 +230,47 @@ def fetch_conversation(%{assigns: %{user: user}} = conn, %{"id" => id}) do Updates metadata of uploaded media object. Derived from [Twitter API endpoint](https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-metadata-create). """ - def update_media(%{assigns: %{user: _}} = conn, %{"media_id" => id} = data) do + def update_media(%{assigns: %{user: user}} = conn, %{"media_id" => id} = data) do + object = Repo.get(Object, id) description = get_in(data, ["alt_text", "text"]) || data["name"] || data["description"] - with %Object{} = object <- Repo.get(Object, id), - is_binary(description) do - new_data = Map.put(object.data, "name", description) + {conn, status, response_body} = + cond do + !object -> + {halt(conn), :not_found, ""} - {:ok, _} = - object - |> Object.change(%{data: new_data}) - |> Repo.update() - end + object.data["actor"] != User.ap_id(user) -> + {halt(conn), :forbidden, "You can only update your own uploads."} + + !is_binary(description) -> + {conn, :not_modified, ""} + + true -> + new_data = Map.put(object.data, "name", description) + + {:ok, _} = + object + |> Object.change(%{data: new_data}) + |> Repo.update() + + {conn, :no_content, ""} + end conn - |> put_status(:no_content) - |> json("") + |> put_status(status) + |> json(response_body) end - def upload(conn, %{"media" => media}) do - response = TwitterAPI.upload(media) + def upload(%{assigns: %{user: user}} = conn, %{"media" => media}) do + response = TwitterAPI.upload(media, user) conn |> put_resp_content_type("application/atom+xml") |> send_resp(200, response) end - def upload_json(conn, %{"media" => media}) do - response = TwitterAPI.upload(media, "json") + def upload_json(%{assigns: %{user: user}} = conn, %{"media" => media}) do + response = TwitterAPI.upload(media, user, "json") conn |> json_reply(200, response) diff --git a/test/support/data_case.ex b/test/support/data_case.ex index 8eff0fd94..9dde6b5e5 100644 --- a/test/support/data_case.ex +++ b/test/support/data_case.ex @@ -36,6 +36,23 @@ defmodule Pleroma.DataCase do :ok end + def ensure_local_uploader(_context) do + uploader = Pleroma.Config.get([Pleroma.Upload, :uploader]) + filters = Pleroma.Config.get([Pleroma.Upload, :filters]) + + unless uploader == Pleroma.Uploaders.Local || filters != [] do + Pleroma.Config.put([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local) + Pleroma.Config.put([Pleroma.Upload, :filters], []) + + on_exit(fn -> + Pleroma.Config.put([Pleroma.Upload, :uploader], uploader) + Pleroma.Config.put([Pleroma.Upload, :filters], filters) + end) + end + + :ok + end + @doc """ A helper that transform changeset errors to a map of messages. diff --git a/test/upload_test.exs b/test/upload_test.exs index b2ce755d2..f2cad4cf0 100644 --- a/test/upload_test.exs +++ b/test/upload_test.exs @@ -3,22 +3,7 @@ defmodule Pleroma.UploadTest do use Pleroma.DataCase describe "Storing a file with the Local uploader" do - setup do - uploader = Pleroma.Config.get([Pleroma.Upload, :uploader]) - filters = Pleroma.Config.get([Pleroma.Upload, :filters]) - - unless uploader == Pleroma.Uploaders.Local || filters != [] do - Pleroma.Config.put([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local) - Pleroma.Config.put([Pleroma.Upload, :filters], []) - - on_exit(fn -> - Pleroma.Config.put([Pleroma.Upload, :uploader], uploader) - Pleroma.Config.put([Pleroma.Upload, :filters], filters) - end) - end - - :ok - end + setup [:ensure_local_uploader] test "returns a media url" do File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg") diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index 098acb59f..b5839cff1 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -804,7 +804,7 @@ test "gets an users media", %{conn: conn} do } media = - TwitterAPI.upload(file, "json") + TwitterAPI.upload(file, user, "json") |> Poison.decode!() {:ok, image_post} = diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs index 478763de7..c07dc6912 100644 --- a/test/web/twitter_api/twitter_api_controller_test.exs +++ b/test/web/twitter_api/twitter_api_controller_test.exs @@ -1254,15 +1254,74 @@ test "it returns users, ordered by similarity", %{conn: conn} do end end - describe "POST /api/media/metadata/create" do - test "it updates `data[name]` of referenced Object with provided value", %{conn: conn} do + describe "POST /api/media/upload" do + setup context do + Pleroma.DataCase.ensure_local_uploader(context) + end + + test "it performs the upload and sets `data[actor]` with AP id of uploader user", %{ + conn: conn + } do user = insert(:user) + + upload_filename = "test/fixtures/image_tmp.jpg" + File.cp!("test/fixtures/image.jpg", upload_filename) + + file = %Plug.Upload{ + content_type: "image/jpg", + path: Path.absname(upload_filename), + filename: "image.jpg" + } + + response = + conn + |> assign(:user, user) + |> put_req_header("content-type", "application/octet-stream") + |> post("/api/media/upload", %{ + "media" => file + }) + |> json_response(:ok) + + assert response["media_id"] + object = Repo.get(Object, response["media_id"]) + assert object + assert object.data["actor"] == User.ap_id(user) + end + end + + describe "POST /api/media/metadata/create" do + setup do object = insert(:note) - description = "Informative description of the image. Initial: #{object.data["name"]}}" + user = User.get_by_ap_id(object.data["actor"]) + %{object: object, user: user} + end + + test "it returns :forbidden status on attempt to modify someone else's upload", %{ + conn: conn, + object: object + } do + initial_description = object.data["name"] + another_user = insert(:user) + + conn + |> assign(:user, another_user) + |> post("/api/media/metadata/create", %{"media_id" => object.id}) + |> json_response(:forbidden) + + object = Repo.get(Object, object.id) + assert object.data["name"] == initial_description + end + + test "it updates `data[name]` of referenced Object with provided value", %{ + conn: conn, + object: object, + user: user + } do + description = "Informative description of the image. Initial value: #{object.data["name"]}}" conn |> assign(:user, user) - |> post("/api/media/metadata/create.json", %{ + |> post("/api/media/metadata/create", %{ "media_id" => object.id, "alt_text" => %{"text" => description} }) diff --git a/test/web/twitter_api/twitter_api_test.exs b/test/web/twitter_api/twitter_api_test.exs index 28230699f..e34fbbabd 100644 --- a/test/web/twitter_api/twitter_api_test.exs +++ b/test/web/twitter_api/twitter_api_test.exs @@ -182,13 +182,14 @@ test "Unblock another user using screen_name" do end test "upload a file" do + user = insert(:user) file = %Plug.Upload{ content_type: "image/jpg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg" } - response = TwitterAPI.upload(file) + response = TwitterAPI.upload(file, user) assert is_binary(response) end From ba345e4c293449871f443669b73c262403237620 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Wed, 5 Dec 2018 13:43:00 +0300 Subject: [PATCH 07/10] [#210] Formatting fix. --- test/web/twitter_api/twitter_api_test.exs | 1 + 1 file changed, 1 insertion(+) diff --git a/test/web/twitter_api/twitter_api_test.exs b/test/web/twitter_api/twitter_api_test.exs index e34fbbabd..032701705 100644 --- a/test/web/twitter_api/twitter_api_test.exs +++ b/test/web/twitter_api/twitter_api_test.exs @@ -183,6 +183,7 @@ test "Unblock another user using screen_name" do test "upload a file" do user = insert(:user) + file = %Plug.Upload{ content_type: "image/jpg", path: Path.absname("test/fixtures/image.jpg"), From c4f3c5e939638905f94cdee53db7a0704a80d133 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Wed, 5 Dec 2018 20:23:28 +0300 Subject: [PATCH 08/10] [#210] Stylistic change. --- lib/pleroma/web/activity_pub/activity_pub.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 39692163f..4eb9d96ab 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -574,7 +574,7 @@ def fetch_activities_bounded(recipients_to, recipients_cc, opts \\ %{}) do def upload(file, opts \\ []) do with {:ok, data} <- Upload.store(file, opts) do - obj_data = if opts[:actor], do: Map.put(data, "actor", opts[:actor]), else: data + obj_data = (opts[:actor] && Map.put(data, "actor", opts[:actor])) || data Repo.insert(%Object{data: obj_data}) end end From 3b5be09f4544ab1b3f6821fd4bbe047f94ef71ac Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Wed, 5 Dec 2018 21:48:21 +0300 Subject: [PATCH 09/10] [#210] Stylistic change. --- lib/pleroma/web/activity_pub/activity_pub.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 4eb9d96ab..39692163f 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -574,7 +574,7 @@ def fetch_activities_bounded(recipients_to, recipients_cc, opts \\ %{}) do def upload(file, opts \\ []) do with {:ok, data} <- Upload.store(file, opts) do - obj_data = (opts[:actor] && Map.put(data, "actor", opts[:actor])) || data + obj_data = if opts[:actor], do: Map.put(data, "actor", opts[:actor]), else: data Repo.insert(%Object{data: obj_data}) end end From 3e90f688f14310e92fe9343f2680c58d74f71cb6 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Thu, 6 Dec 2018 10:26:17 +0300 Subject: [PATCH 10/10] [#210] Mastodon: actor storing for media uploads, ownership check to update_media. Refactoring. --- lib/pleroma/object.ex | 9 ++++- lib/pleroma/web/activity_pub/activity_pub.ex | 8 ++++- .../mastodon_api/mastodon_api_controller.ex | 34 +++++++++---------- lib/pleroma/web/twitter_api/twitter_api.ex | 6 +--- .../web/twitter_api/twitter_api_controller.ex | 2 +- .../mastodon_api_controller_test.exs | 6 +++- 6 files changed, 38 insertions(+), 27 deletions(-) diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index 03a75dfbd..31c8dd5bd 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -1,6 +1,6 @@ defmodule Pleroma.Object do use Ecto.Schema - alias Pleroma.{Repo, Object, Activity} + alias Pleroma.{Repo, Object, User, Activity} import Ecto.{Query, Changeset} schema "objects" do @@ -31,6 +31,13 @@ def normalize(obj) when is_map(obj), do: Object.get_by_ap_id(obj["id"]) def normalize(ap_id) when is_binary(ap_id), do: Object.get_by_ap_id(ap_id) def normalize(_), do: nil + # Owned objects can only be mutated by their owner + def authorize_mutation(%Object{data: %{"actor" => actor}}, %User{ap_id: ap_id}), + do: actor == ap_id + + # Legacy objects can be mutated by anybody + def authorize_mutation(%Object{}, %User{}), do: true + if Mix.env() == :test do def get_cached_by_ap_id(ap_id) do get_by_ap_id(ap_id) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 39692163f..aaf9d3854 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -574,7 +574,13 @@ def fetch_activities_bounded(recipients_to, recipients_cc, opts \\ %{}) do def upload(file, opts \\ []) do with {:ok, data} <- Upload.store(file, opts) do - obj_data = if opts[:actor], do: Map.put(data, "actor", opts[:actor]), else: data + obj_data = + if opts[:actor] do + Map.put(data, "actor", opts[:actor]) + else + data + end + Repo.insert(%Object{data: obj_data}) end end diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 543fdf416..ef204f7f3 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -433,33 +433,31 @@ def relationships(%{assigns: %{user: user}} = conn, _) do |> json([]) end - def update_media(%{assigns: %{user: _}} = conn, data) do + def update_media(%{assigns: %{user: user}} = conn, data) do with %Object{} = object <- Repo.get(Object, data["id"]), + true <- Object.authorize_mutation(object, user), true <- is_binary(data["description"]), description <- data["description"] do new_data = %{object.data | "name" => description} - change = Object.change(object, %{data: new_data}) - {:ok, _} = Repo.update(change) + {:ok, _} = + object + |> Object.change(%{data: new_data}) + |> Repo.update() - data = - new_data - |> Map.put("id", object.id) - - render(conn, StatusView, "attachment.json", %{attachment: data}) + attachment_data = Map.put(new_data, "id", object.id) + render(conn, StatusView, "attachment.json", %{attachment: attachment_data}) end end - def upload(%{assigns: %{user: _}} = conn, %{"file" => file} = data) do - with {:ok, object} <- ActivityPub.upload(file, description: Map.get(data, "description")) do - change = Object.change(object, %{data: object.data}) - {:ok, object} = Repo.update(change) - - objdata = - object.data - |> Map.put("id", object.id) - - render(conn, StatusView, "attachment.json", %{attachment: objdata}) + def upload(%{assigns: %{user: user}} = conn, %{"file" => file} = data) do + with {:ok, object} <- + ActivityPub.upload(file, + actor: User.ap_id(user), + description: Map.get(data, "description") + ) do + attachment_data = Map.put(object.data, "id", object.id) + render(conn, StatusView, "attachment.json", %{attachment: attachment_data}) end end diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index b9468ab03..9c485d965 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -93,12 +93,8 @@ def unfav(%User{} = user, ap_id_or_id) do end end - def ap_upload(%Plug.Upload{} = file, %User{} = user) do - ActivityPub.upload(file, actor: User.ap_id(user)) - end - def upload(%Plug.Upload{} = file, %User{} = user, format \\ "xml") do - {:ok, object} = ap_upload(file, user) + {:ok, object} = ActivityPub.upload(file, actor: User.ap_id(user)) url = List.first(object.data["url"]) href = url["href"] diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index 2f12131e7..c19ee230f 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -239,7 +239,7 @@ def update_media(%{assigns: %{user: user}} = conn, %{"media_id" => id} = data) d !object -> {halt(conn), :not_found, ""} - object.data["actor"] != User.ap_id(user) -> + !Object.authorize_mutation(object, user) -> {halt(conn), :forbidden, "You can only update your own uploads."} !is_binary(description) -> diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index b5839cff1..d952cecc8 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -2,7 +2,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do use Pleroma.Web.ConnCase alias Pleroma.Web.TwitterAPI.TwitterAPI - alias Pleroma.{Repo, User, Activity, Notification} + alias Pleroma.{Repo, User, Object, Activity, Notification} alias Pleroma.Web.{OStatus, CommonAPI} alias Pleroma.Web.ActivityPub.ActivityPub @@ -959,6 +959,10 @@ test "media upload", %{conn: conn} do assert media["type"] == "image" assert media["description"] == desc + assert media["id"] + + object = Repo.get(Object, media["id"]) + assert object.data["actor"] == User.ap_id(user) end test "hashtag timeline", %{conn: conn} do