Merge branch 'develop' of git.pleroma.social:pleroma/pleroma into chat-federation...
authorlain <lain@soykaf.club>
Fri, 10 Jul 2020 10:26:53 +0000 (12:26 +0200)
committerlain <lain@soykaf.club>
Fri, 10 Jul 2020 10:26:53 +0000 (12:26 +0200)
12 files changed:
1  2 
CHANGELOG.md
docs/API/differences_in_mastoapi_responses.md
lib/pleroma/user.ex
lib/pleroma/web/activity_pub/activity_pub.ex
lib/pleroma/web/api_spec/operations/account_operation.ex
lib/pleroma/web/api_spec/schemas/account.ex
lib/pleroma/web/mastodon_api/controllers/account_controller.ex
lib/pleroma/web/mastodon_api/views/account_view.ex
test/web/activity_pub/activity_pub_test.exs
test/web/activity_pub/object_validators/chat_validation_test.exs
test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs
test/web/mastodon_api/views/account_view_test.exs

diff --cc CHANGELOG.md
Simple merge
index 4514a7d598a74b61635dcc81b0b3c8176c472911,03c7f4608fd02fd202b99f4a1b7ebad55ae02a09..65f9f1aefc52d4be68300188089508e75f5800bf
@@@ -71,7 -71,7 +71,8 @@@ Has these additional fields under the `
  - `unread_conversation_count`: The count of unread conversations. Only returned to the account owner.
  - `unread_notifications_count`: The count of unread notifications. Only returned to the account owner.
  - `notification_settings`: object, can be absent. See `/api/pleroma/notification_settings` for the parameters/keys returned.
 +- `accepts_chat_messages`: boolean, but can be null if we don't have that information about a user
+ - `favicon`: nullable URL string, Favicon image of the user's instance
  
  ### Source
  
@@@ -183,11 -183,12 +184,13 @@@ Additional parameters can be added to t
  - `pleroma_settings_store` - Opaque user settings to be saved on the backend.
  - `skip_thread_containment` - if true, skip filtering out broken threads
  - `allow_following_move` - if true, allows automatically follow moved following accounts
- - `pleroma_background_image` - sets the background image of the user.
+ - `pleroma_background_image` - sets the background image of the user. Can be set to "" (an empty string) to reset.
  - `discoverable` - if true, discovery of this account in search results and other services is allowed.
  - `actor_type` - the type of this account.
 +- `accepts_chat_messages` - if false, this account will reject all chat messages.
  
+ All images (avatar, banner and background) can be reset to the default by sending an empty string ("") instead of a file.
  ### Pleroma Settings Store
  
  Pleroma has mechanism that allows frontends to save blobs of json for each user on the backend. This can be used to save frontend-specific settings for a user that the backend does not need to know about.
index 712bc30478c59c238804dda9450d4226e1c4e592,0078f98317777a91e2017f03936da22eae6647d1..b9989f9018194122f2499918afedf2f88d73ad4f
@@@ -624,9 -618,8 +621,9 @@@ defmodule Pleroma.User d
    def force_password_reset(user), do: update_password_reset_pending(user, true)
  
    def register_changeset(struct, params \\ %{}, opts \\ []) do
-     bio_limit = Pleroma.Config.get([:instance, :user_bio_length], 5000)
-     name_limit = Pleroma.Config.get([:instance, :user_name_length], 100)
+     bio_limit = Config.get([:instance, :user_bio_length], 5000)
+     name_limit = Config.get([:instance, :user_name_length], 100)
 +    params = Map.put_new(params, :accepts_chat_messages, true)
  
      need_confirmation? =
        if is_nil(opts[:need_confirmation]) do
index 3a84a1593d67c4f54db15485c70726ce83b93d0d,e6f163cb757153dd825dd3d9b545128699eb6d25..cf148bc9d944dea753aed36edd64dd3bf25bd39c
@@@ -103,7 -103,12 +103,13 @@@ defmodule Pleroma.Web.ApiSpec.Schemas.A
              description:
                "A generic map of settings for frontends. Opaque to the backend. Only returned in `verify_credentials` and `update_credentials`"
            },
-           accepts_chat_messages: %Schema{type: :boolean, nullable: true}
++          accepts_chat_messages: %Schema{type: :boolean, nullable: true},
+           favicon: %Schema{
+             type: :string,
+             format: :uri,
+             nullable: true,
+             description: "Favicon image of the user's instance"
+           }
          }
        },
        source: %Schema{
index 6a643bfcc7b74e2e792f18ccc46538b7e0dcf0aa,2feba47782dbb553908a6601a329086a3b56c3bf..bc9745044a4bef61f2b0ae00786797b37f987858
@@@ -246,7 -258,7 +258,8 @@@ defmodule Pleroma.Web.MastodonAPI.Accou
          relationship: relationship,
          skip_thread_containment: user.skip_thread_containment,
          background_image: image_url(user.background) |> MediaProxy.url(),
-         accepts_chat_messages: user.accepts_chat_messages
++        accepts_chat_messages: user.accepts_chat_messages,
+         favicon: favicon
        }
      }
      |> maybe_put_role(user, opts[:for])
index 0000000000000000000000000000000000000000,ec1e497fa32e59547d67d41217ce88776a5aba85..50bf03515dff31ab30905a920d1bc606e1b655c3
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,200 +1,211 @@@
+ # Pleroma: A lightweight social networking server
+ # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+ # SPDX-License-Identifier: AGPL-3.0-only
+ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ChatValidationTest do
+   use Pleroma.DataCase
+   alias Pleroma.Object
+   alias Pleroma.Web.ActivityPub.ActivityPub
+   alias Pleroma.Web.ActivityPub.Builder
+   alias Pleroma.Web.ActivityPub.ObjectValidator
+   alias Pleroma.Web.CommonAPI
+   import Pleroma.Factory
+   describe "chat message create activities" do
+     test "it is invalid if the object already exists" do
+       user = insert(:user)
+       recipient = insert(:user)
+       {:ok, activity} = CommonAPI.post_chat_message(user, recipient, "hey")
+       object = Object.normalize(activity, false)
+       {:ok, create_data, _} = Builder.create(user, object.data, [recipient.ap_id])
+       {:error, cng} = ObjectValidator.validate(create_data, [])
+       assert {:object, {"The object to create already exists", []}} in cng.errors
+     end
+     test "it is invalid if the object data has a different `to` or `actor` field" do
+       user = insert(:user)
+       recipient = insert(:user)
+       {:ok, object_data, _} = Builder.chat_message(recipient, user.ap_id, "Hey")
+       {:ok, create_data, _} = Builder.create(user, object_data, [recipient.ap_id])
+       {:error, cng} = ObjectValidator.validate(create_data, [])
+       assert {:to, {"Recipients don't match with object recipients", []}} in cng.errors
+       assert {:actor, {"Actor doesn't match with object actor", []}} in cng.errors
+     end
+   end
+   describe "chat messages" do
+     setup do
+       clear_config([:instance, :remote_limit])
+       user = insert(:user)
+       recipient = insert(:user, local: false)
+       {:ok, valid_chat_message, _} = Builder.chat_message(user, recipient.ap_id, "hey :firefox:")
+       %{user: user, recipient: recipient, valid_chat_message: valid_chat_message}
+     end
+     test "let's through some basic html", %{user: user, recipient: recipient} do
+       {:ok, valid_chat_message, _} =
+         Builder.chat_message(
+           user,
+           recipient.ap_id,
+           "hey <a href='https://example.org'>example</a> <script>alert('uguu')</script>"
+         )
+       assert {:ok, object, _meta} = ObjectValidator.validate(valid_chat_message, [])
+       assert object["content"] ==
+                "hey <a href=\"https://example.org\">example</a> alert(&#39;uguu&#39;)"
+     end
+     test "validates for a basic object we build", %{valid_chat_message: valid_chat_message} do
+       assert {:ok, object, _meta} = ObjectValidator.validate(valid_chat_message, [])
+       assert Map.put(valid_chat_message, "attachment", nil) == object
+     end
+     test "validates for a basic object with an attachment", %{
+       valid_chat_message: valid_chat_message,
+       user: user
+     } do
+       file = %Plug.Upload{
+         content_type: "image/jpg",
+         path: Path.absname("test/fixtures/image.jpg"),
+         filename: "an_image.jpg"
+       }
+       {:ok, attachment} = ActivityPub.upload(file, actor: user.ap_id)
+       valid_chat_message =
+         valid_chat_message
+         |> Map.put("attachment", attachment.data)
+       assert {:ok, object, _meta} = ObjectValidator.validate(valid_chat_message, [])
+       assert object["attachment"]
+     end
+     test "validates for a basic object with an attachment in an array", %{
+       valid_chat_message: valid_chat_message,
+       user: user
+     } do
+       file = %Plug.Upload{
+         content_type: "image/jpg",
+         path: Path.absname("test/fixtures/image.jpg"),
+         filename: "an_image.jpg"
+       }
+       {:ok, attachment} = ActivityPub.upload(file, actor: user.ap_id)
+       valid_chat_message =
+         valid_chat_message
+         |> Map.put("attachment", [attachment.data])
+       assert {:ok, object, _meta} = ObjectValidator.validate(valid_chat_message, [])
+       assert object["attachment"]
+     end
+     test "validates for a basic object with an attachment but without content", %{
+       valid_chat_message: valid_chat_message,
+       user: user
+     } do
+       file = %Plug.Upload{
+         content_type: "image/jpg",
+         path: Path.absname("test/fixtures/image.jpg"),
+         filename: "an_image.jpg"
+       }
+       {:ok, attachment} = ActivityPub.upload(file, actor: user.ap_id)
+       valid_chat_message =
+         valid_chat_message
+         |> Map.put("attachment", attachment.data)
+         |> Map.delete("content")
+       assert {:ok, object, _meta} = ObjectValidator.validate(valid_chat_message, [])
+       assert object["attachment"]
+     end
+     test "does not validate if the message has no content", %{
+       valid_chat_message: valid_chat_message
+     } do
+       contentless =
+         valid_chat_message
+         |> Map.delete("content")
+       refute match?({:ok, _object, _meta}, ObjectValidator.validate(contentless, []))
+     end
+     test "does not validate if the message is longer than the remote_limit", %{
+       valid_chat_message: valid_chat_message
+     } do
+       Pleroma.Config.put([:instance, :remote_limit], 2)
+       refute match?({:ok, _object, _meta}, ObjectValidator.validate(valid_chat_message, []))
+     end
+     test "does not validate if the recipient is blocking the actor", %{
+       valid_chat_message: valid_chat_message,
+       user: user,
+       recipient: recipient
+     } do
+       Pleroma.User.block(recipient, user)
+       refute match?({:ok, _object, _meta}, ObjectValidator.validate(valid_chat_message, []))
+     end
++    test "does not validate if the recipient is not accepting chat messages", %{
++      valid_chat_message: valid_chat_message,
++      recipient: recipient
++    } do
++      recipient
++      |> Ecto.Changeset.change(%{accepts_chat_messages: false})
++      |> Pleroma.Repo.update!()
++
++      refute match?({:ok, _object, _meta}, ObjectValidator.validate(valid_chat_message, []))
++    end
++
+     test "does not validate if the actor or the recipient is not in our system", %{
+       valid_chat_message: valid_chat_message
+     } do
+       chat_message =
+         valid_chat_message
+         |> Map.put("actor", "https://raymoo.com/raymoo")
+       {:error, _} = ObjectValidator.validate(chat_message, [])
+       chat_message =
+         valid_chat_message
+         |> Map.put("to", ["https://raymoo.com/raymoo"])
+       {:error, _} = ObjectValidator.validate(chat_message, [])
+     end
+     test "does not validate for a message with multiple recipients", %{
+       valid_chat_message: valid_chat_message,
+       user: user,
+       recipient: recipient
+     } do
+       chat_message =
+         valid_chat_message
+         |> Map.put("to", [user.ap_id, recipient.ap_id])
+       assert {:error, _} = ObjectValidator.validate(chat_message, [])
+     end
+     test "does not validate if it doesn't concern local users" do
+       user = insert(:user, local: false)
+       recipient = insert(:user, local: false)
+       {:ok, valid_chat_message, _} = Builder.chat_message(user, recipient.ap_id, "hey")
+       assert {:error, _} = ObjectValidator.validate(valid_chat_message, [])
+     end
+   end
+ end