From fe13a1d78c13fbe7b3027d442a6f6906440e5acc Mon Sep 17 00:00:00 2001 From: Alex S Date: Wed, 10 Apr 2019 17:57:41 +0700 Subject: [PATCH 01/23] adding notify_email setting for trigger emails --- config/config.exs | 1 + config/test.exs | 4 ++ docs/config.md | 7 ++- lib/mix/tasks/pleroma/instance.ex | 17 ++++- lib/mix/tasks/pleroma/sample_config.eex | 2 +- lib/pleroma/emails/admin_email.ex | 4 +- lib/pleroma/emails/user_email.ex | 2 +- test/tasks/instance.exs | 62 +++++++++++++++++++ .../admin_api/admin_api_controller_test.exs | 10 ++- .../mastodon_api_controller_test.exs | 5 +- .../twitter_api_controller_test.exs | 23 +++++-- test/web/twitter_api/twitter_api_test.exs | 11 +++- 12 files changed, 132 insertions(+), 16 deletions(-) create mode 100644 test/tasks/instance.exs diff --git a/config/config.exs b/config/config.exs index 3462a37f7..9edec8dc3 100644 --- a/config/config.exs +++ b/config/config.exs @@ -160,6 +160,7 @@ config :pleroma, :instance, name: "Pleroma", email: "example@example.com", + notify_email: "noreply@example.com", description: "A Pleroma instance, an alternative fediverse server", limit: 5_000, remote_limit: 100_000, diff --git a/config/test.exs b/config/test.exs index 894fa8d3d..2c4beaade 100644 --- a/config/test.exs +++ b/config/test.exs @@ -23,6 +23,10 @@ config :pleroma, Pleroma.Mailer, adapter: Swoosh.Adapters.Test +config :pleroma, :instance, + email: "admin@example.com", + notify_email: "noreply@example.com" + # Configure your database config :pleroma, Pleroma.Repo, adapter: Ecto.Adapters.Postgres, diff --git a/docs/config.md b/docs/config.md index b5ea58746..7d3a482b3 100644 --- a/docs/config.md +++ b/docs/config.md @@ -63,6 +63,7 @@ config :pleroma, Pleroma.Mailer, ## :instance * `name`: The instance’s name * `email`: Email used to reach an Administrator/Moderator of the instance +* `notify_email`: Email used for notifications. * `description`: The instance’s description, can be seen in nodeinfo and ``/api/v1/instance`` * `limit`: Posts character limit (CW/Subject included in the counter) * `remote_limit`: Hard character limit beyond which remote posts will be dropped. @@ -427,7 +428,7 @@ Pleroma account will be created with the same name as the LDAP user name. Authentication / authorization settings. -* `auth_template`: authentication form template. By default it's `show.html` which corresponds to `lib/pleroma/web/templates/o_auth/o_auth/show.html.eex`. +* `auth_template`: authentication form template. By default it's `show.html` which corresponds to `lib/pleroma/web/templates/o_auth/o_auth/show.html.eex`. * `oauth_consumer_template`: OAuth consumer mode authentication form template. By default it's `consumer.html` which corresponds to `lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex`. * `oauth_consumer_strategies`: the list of enabled OAuth consumer strategies; by default it's set by OAUTH_CONSUMER_STRATEGIES environment variable. @@ -440,7 +441,7 @@ Note: each strategy is shipped as a separate dependency; in order to get the str e.g. `OAUTH_CONSUMER_STRATEGIES="twitter facebook google microsoft" mix deps.get`. The server should also be started with `OAUTH_CONSUMER_STRATEGIES="..." mix phx.server` in case you enable any strategies. -Note: each strategy requires separate setup (on external provider side and Pleroma side). Below are the guidelines on setting up most popular strategies. +Note: each strategy requires separate setup (on external provider side and Pleroma side). Below are the guidelines on setting up most popular strategies. * For Twitter, [register an app](https://developer.twitter.com/en/apps), configure callback URL to https:///oauth/twitter/callback @@ -475,7 +476,7 @@ config :ueberauth, Ueberauth.Strategy.Google.OAuth, config :ueberauth, Ueberauth.Strategy.Microsoft.OAuth, client_id: System.get_env("MICROSOFT_CLIENT_ID"), client_secret: System.get_env("MICROSOFT_CLIENT_SECRET") - + config :ueberauth, Ueberauth, providers: [ microsoft: {Ueberauth.Strategy.Microsoft, [callback_params: []]} diff --git a/lib/mix/tasks/pleroma/instance.ex b/lib/mix/tasks/pleroma/instance.ex index 8f8d86a11..6cee8d630 100644 --- a/lib/mix/tasks/pleroma/instance.ex +++ b/lib/mix/tasks/pleroma/instance.ex @@ -24,10 +24,12 @@ defmodule Mix.Tasks.Pleroma.Instance do - `--domain DOMAIN` - the domain of your instance - `--instance-name INSTANCE_NAME` - the name of your instance - `--admin-email ADMIN_EMAIL` - the email address of the instance admin + - `--notify-email NOTIFY_EMAIL` - email address for notifications - `--dbhost HOSTNAME` - the hostname of the PostgreSQL database to use - `--dbname DBNAME` - the name of the database to use - `--dbuser DBUSER` - the user (aka role) to use for the database connection - `--dbpass DBPASS` - the password to use for the database connection + - `--indexable Y/N` - Allow/disallow indexing site by search engines """ def run(["gen" | rest]) do @@ -41,10 +43,12 @@ def run(["gen" | rest]) do domain: :string, instance_name: :string, admin_email: :string, + notify_email: :string, dbhost: :string, dbname: :string, dbuser: :string, - dbpass: :string + dbpass: :string, + indexable: :string ], aliases: [ o: :output, @@ -61,7 +65,7 @@ def run(["gen" | rest]) do will_overwrite = Enum.filter(paths, &File.exists?/1) proceed? = Enum.empty?(will_overwrite) or Keyword.get(options, :force, false) - unless not proceed? do + if proceed? do [domain, port | _] = String.split( Common.get_option( @@ -81,6 +85,14 @@ def run(["gen" | rest]) do email = Common.get_option(options, :admin_email, "What is your admin email address?") + notify_email = + Common.get_option( + options, + :notify_email, + "What email address do you want to use for sending email notifications?", + email + ) + indexable = Common.get_option( options, @@ -122,6 +134,7 @@ def run(["gen" | rest]) do domain: domain, port: port, email: email, + notify_email: notify_email, name: name, dbhost: dbhost, dbname: dbname, diff --git a/lib/mix/tasks/pleroma/sample_config.eex b/lib/mix/tasks/pleroma/sample_config.eex index 1c935c0d8..52bd57cb7 100644 --- a/lib/mix/tasks/pleroma/sample_config.eex +++ b/lib/mix/tasks/pleroma/sample_config.eex @@ -13,6 +13,7 @@ config :pleroma, Pleroma.Web.Endpoint, config :pleroma, :instance, name: "<%= name %>", email: "<%= email %>", + notify_email: "<%= notify_email %>", limit: 5000, registrations_open: true, dedupe_media: false @@ -75,4 +76,3 @@ config :web_push_encryption, :vapid_details, # storage_url: "https://swift-endpoint.prodider.com/v1/AUTH_/", # object_url: "https://cdn-endpoint.provider.com/" # - diff --git a/lib/pleroma/emails/admin_email.ex b/lib/pleroma/emails/admin_email.ex index afefccec5..59d571c2a 100644 --- a/lib/pleroma/emails/admin_email.ex +++ b/lib/pleroma/emails/admin_email.ex @@ -11,7 +11,7 @@ defmodule Pleroma.AdminEmail do defp instance_config, do: Pleroma.Config.get(:instance) defp instance_name, do: instance_config()[:name] - defp instance_email, do: instance_config()[:email] + defp instance_notify_email, do: instance_config()[:notify_email] defp user_url(user) do Helpers.o_status_url(Pleroma.Web.Endpoint, :feed_redirect, user.nickname) @@ -59,7 +59,7 @@ def report(to, reporter, account, statuses, comment) do new() |> to({to.name, to.email}) - |> from({instance_name(), instance_email()}) + |> from({instance_name(), instance_notify_email()}) |> reply_to({reporter.name, reporter.email}) |> subject("#{instance_name()} Report") |> html_body(html_body) diff --git a/lib/pleroma/emails/user_email.ex b/lib/pleroma/emails/user_email.ex index a3a09e96c..34dff782a 100644 --- a/lib/pleroma/emails/user_email.ex +++ b/lib/pleroma/emails/user_email.ex @@ -15,7 +15,7 @@ defp instance_config, do: Pleroma.Config.get(:instance) defp instance_name, do: instance_config()[:name] defp sender do - {instance_name(), instance_config()[:email]} + {instance_name(), instance_config()[:notify_email]} end defp recipient(email, nil), do: email diff --git a/test/tasks/instance.exs b/test/tasks/instance.exs new file mode 100644 index 000000000..6917a2376 --- /dev/null +++ b/test/tasks/instance.exs @@ -0,0 +1,62 @@ +defmodule Pleroma.InstanceTest do + use ExUnit.Case, async: true + + setup do + File.mkdir_p!(tmp_path()) + on_exit(fn -> File.rm_rf(tmp_path()) end) + :ok + end + + defp tmp_path do + "/tmp/generated_files/" + end + + test "running gen" do + mix_task = fn -> + Mix.Tasks.Pleroma.Instance.run([ + "gen", + "--output", + tmp_path() <> "generated_config.exs", + "--output-psql", + tmp_path() <> "setup.psql", + "--domain", + "test.pleroma.social", + "--instance-name", + "Pleroma", + "--admin-email", + "admin@example.com", + "--notify-email", + "notify@example.com", + "--dbhost", + "dbhost", + "--dbname", + "dbname", + "--dbuser", + "dbuser", + "--dbpass", + "dbpass", + "--indexable", + "y" + ]) + end + + ExUnit.CaptureIO.capture_io(fn -> + mix_task.() + end) + + generated_config = File.read!(tmp_path() <> "generated_config.exs") + assert generated_config =~ "host: \"test.pleroma.social\"" + assert generated_config =~ "name: \"Pleroma\"" + assert generated_config =~ "email: \"admin@example.com\"" + assert generated_config =~ "notify_email: \"notify@example.com\"" + assert generated_config =~ "hostname: \"dbhost\"" + assert generated_config =~ "database: \"dbname\"" + assert generated_config =~ "username: \"dbuser\"" + assert generated_config =~ "password: \"dbpass\"" + assert File.read!(tmp_path() <> "setup.psql") == generated_setup_psql() + end + + defp generated_setup_psql do + ~s(CREATE USER dbuser WITH ENCRYPTED PASSWORD 'dbpass';\nCREATE DATABASE dbname OWNER dbuser;\n\\c dbname;\n--Extensions made by ecto.migrate that need superuser access\nCREATE EXTENSION IF NOT EXISTS citext;\nCREATE EXTENSION IF NOT EXISTS pg_trgm;\nCREATE EXTENSION IF NOT EXISTS \"uuid-ossp\";\n) + end +end diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index ca6bd0e97..7b1f6d53a 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -316,13 +316,21 @@ test "sends invitation and returns 204", %{conn: conn, user: user} do assert token_record refute token_record.used - Swoosh.TestAssertions.assert_email_sent( + notify_email = Pleroma.Config.get([:instance, :notify_email]) + instance_name = Pleroma.Config.get([:instance, :name]) + + email = Pleroma.UserEmail.user_invitation_email( user, token_record, recipient_email, recipient_name ) + + Swoosh.TestAssertions.assert_email_sent( + from: {instance_name, notify_email}, + to: {recipient_name, recipient_email}, + html_body: email.html_body ) end diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index e16862a48..24e258d66 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -1910,13 +1910,14 @@ test "get instance information", %{conn: conn} do conn = get(conn, "/api/v1/instance") assert result = json_response(conn, 200) + email = Pleroma.Config.get([:instance, :email]) # Note: not checking for "max_toot_chars" since it's optional assert %{ "uri" => _, "title" => _, "description" => _, "version" => _, - "email" => _, + "email" => from_config_email, "urls" => %{ "streaming_api" => _ }, @@ -1925,6 +1926,8 @@ test "get instance information", %{conn: conn} do "languages" => _, "registrations" => _ } = result + + assert email == from_config_email end test "get instance stats", %{conn: conn} do diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs index 72b7ea85e..e7293e384 100644 --- a/test/web/twitter_api/twitter_api_controller_test.exs +++ b/test/web/twitter_api/twitter_api_controller_test.exs @@ -22,8 +22,9 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do alias Pleroma.Web.TwitterAPI.TwitterAPI alias Pleroma.Web.TwitterAPI.UserView - import Pleroma.Factory import Mock + import Pleroma.Factory + import Swoosh.TestAssertions @banner "data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7" @@ -1063,8 +1064,14 @@ test "it creates a PasswordResetToken record for user", %{user: user} do test "it sends an email to user", %{user: user} do token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id) - Swoosh.TestAssertions.assert_email_sent( - Pleroma.UserEmail.password_reset_email(user, token_record.token) + email = Pleroma.UserEmail.password_reset_email(user, token_record.token) + notify_email = Pleroma.Config.get([:instance, :notify_email]) + instance_name = Pleroma.Config.get([:instance, :name]) + + assert_email_sent( + from: {instance_name, notify_email}, + to: {user.name, user.email}, + html_body: email.html_body ) end end @@ -1163,7 +1170,15 @@ test "it sends confirmation email", %{conn: conn, user: user} do |> assign(:user, user) |> post("/api/account/resend_confirmation_email?email=#{user.email}") - Swoosh.TestAssertions.assert_email_sent(Pleroma.UserEmail.account_confirmation_email(user)) + email = Pleroma.UserEmail.account_confirmation_email(user) + notify_email = Pleroma.Config.get([:instance, :notify_email]) + instance_name = Pleroma.Config.get([:instance, :name]) + + assert_email_sent( + from: {instance_name, notify_email}, + to: {user.name, user.email}, + html_body: email.html_body + ) end end diff --git a/test/web/twitter_api/twitter_api_test.exs b/test/web/twitter_api/twitter_api_test.exs index 6c00244de..24e46408c 100644 --- a/test/web/twitter_api/twitter_api_test.exs +++ b/test/web/twitter_api/twitter_api_test.exs @@ -321,7 +321,16 @@ test "it sends confirmation email if :account_activation_required is specified i assert user.info.confirmation_pending - Swoosh.TestAssertions.assert_email_sent(Pleroma.UserEmail.account_confirmation_email(user)) + email = Pleroma.UserEmail.account_confirmation_email(user) + + notify_email = Pleroma.Config.get([:instance, :notify_email]) + instance_name = Pleroma.Config.get([:instance, :name]) + + Swoosh.TestAssertions.assert_email_sent( + from: {instance_name, notify_email}, + to: {user.name, user.email}, + html_body: email.html_body + ) end test "it registers a new user and parses mentions in the bio" do From a64eb2b3893cee61f50d89b6ad4d273031ef0ea9 Mon Sep 17 00:00:00 2001 From: Alex S Date: Sat, 13 Apr 2019 12:20:36 +0700 Subject: [PATCH 02/23] fallback to the old behaviour admin and user mailers --- lib/pleroma/emails/admin_email.ex | 5 ++++- lib/pleroma/emails/user_email.ex | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/emails/admin_email.ex b/lib/pleroma/emails/admin_email.ex index 59d571c2a..e730410c5 100644 --- a/lib/pleroma/emails/admin_email.ex +++ b/lib/pleroma/emails/admin_email.ex @@ -11,7 +11,10 @@ defmodule Pleroma.AdminEmail do defp instance_config, do: Pleroma.Config.get(:instance) defp instance_name, do: instance_config()[:name] - defp instance_notify_email, do: instance_config()[:notify_email] + + defp instance_notify_email do + Keyword.get(instance_config(), :notify_email, instance_config()[:email]) + end defp user_url(user) do Helpers.o_status_url(Pleroma.Web.Endpoint, :feed_redirect, user.nickname) diff --git a/lib/pleroma/emails/user_email.ex b/lib/pleroma/emails/user_email.ex index 34dff782a..ca0772f57 100644 --- a/lib/pleroma/emails/user_email.ex +++ b/lib/pleroma/emails/user_email.ex @@ -15,7 +15,8 @@ defp instance_config, do: Pleroma.Config.get(:instance) defp instance_name, do: instance_config()[:name] defp sender do - {instance_name(), instance_config()[:notify_email]} + email = Keyword.get(instance_config(), :notify_email, instance_config()[:email]) + {instance_name(), email} end defp recipient(email, nil), do: email From c5d0fffeaf64123334f62343d752467683a67229 Mon Sep 17 00:00:00 2001 From: Alex S Date: Sat, 13 Apr 2019 14:55:42 +0700 Subject: [PATCH 03/23] naming fix --- test/web/admin_api/admin_api_controller_test.exs | 2 +- test/web/twitter_api/twitter_api_controller_test.exs | 4 ++-- test/web/twitter_api/twitter_api_test.exs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index ca7794d70..b3167a861 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -321,7 +321,7 @@ test "sends invitation and returns 204", %{conn: conn, user: user} do instance_name = Pleroma.Config.get([:instance, :name]) email = - Pleroma.UserEmail.user_invitation_email( + Pleroma.Emails.UserEmail.user_invitation_email( user, token_record, recipient_email, diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs index e7293e384..9a9630c19 100644 --- a/test/web/twitter_api/twitter_api_controller_test.exs +++ b/test/web/twitter_api/twitter_api_controller_test.exs @@ -1064,7 +1064,7 @@ test "it creates a PasswordResetToken record for user", %{user: user} do test "it sends an email to user", %{user: user} do token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id) - email = Pleroma.UserEmail.password_reset_email(user, token_record.token) + email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token) notify_email = Pleroma.Config.get([:instance, :notify_email]) instance_name = Pleroma.Config.get([:instance, :name]) @@ -1170,7 +1170,7 @@ test "it sends confirmation email", %{conn: conn, user: user} do |> assign(:user, user) |> post("/api/account/resend_confirmation_email?email=#{user.email}") - email = Pleroma.UserEmail.account_confirmation_email(user) + email = Pleroma.Emails.UserEmail.account_confirmation_email(user) notify_email = Pleroma.Config.get([:instance, :notify_email]) instance_name = Pleroma.Config.get([:instance, :name]) diff --git a/test/web/twitter_api/twitter_api_test.exs b/test/web/twitter_api/twitter_api_test.exs index b61e2a24c..3440ad268 100644 --- a/test/web/twitter_api/twitter_api_test.exs +++ b/test/web/twitter_api/twitter_api_test.exs @@ -325,7 +325,7 @@ test "it sends confirmation email if :account_activation_required is specified i assert user.info.confirmation_pending - email = Pleroma.UserEmail.account_confirmation_email(user) + email = Pleroma.Emails.UserEmail.account_confirmation_email(user) notify_email = Pleroma.Config.get([:instance, :notify_email]) instance_name = Pleroma.Config.get([:instance, :name]) From 679a8ef629bf08f2ade88ea358b661589e29264f Mon Sep 17 00:00:00 2001 From: eugenijm Date: Sun, 14 Apr 2019 05:15:03 +0300 Subject: [PATCH 04/23] Assign reblogged in the Mastodon reblog status view --- .../web/mastodon_api/views/status_view.ex | 14 ++++--- .../mastodon_api_controller_test.exs | 37 ++++++++++++++++++- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index bdc33186e..a9f607aa5 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -54,6 +54,11 @@ defp get_context_id(%{data: %{"context" => context}}) when is_binary(context), defp get_context_id(_), do: nil + defp reblogged?(activity, user) do + object = activity.data["object"] || %{} + present?(user && user.ap_id in (object["announcements"] || [])) + end + def render("index.json", opts) do replied_to_activities = get_replied_to_activities(opts.activities) @@ -72,8 +77,8 @@ def render( user = get_user(activity.data["actor"]) created_at = Utils.to_masto_date(activity.data["published"]) - reblogged = Activity.get_create_by_object_ap_id(object) - reblogged = render("status.json", Map.put(opts, :activity, reblogged)) + reblogged_activity = Activity.get_create_by_object_ap_id(object) + reblogged = render("status.json", Map.put(opts, :activity, reblogged_activity)) mentions = activity.recipients @@ -94,7 +99,7 @@ def render( reblogs_count: 0, replies_count: 0, favourites_count: 0, - reblogged: false, + reblogged: reblogged?(reblogged_activity, opts[:for]), favourited: false, bookmarked: false, muted: false, @@ -132,7 +137,6 @@ def render("status.json", %{activity: %{data: %{"object" => object}} = activity} |> Enum.filter(& &1) |> Enum.map(fn user -> AccountView.render("mention.json", %{user: user}) end) - repeated = opts[:for] && opts[:for].ap_id in (object["announcements"] || []) favorited = opts[:for] && opts[:for].ap_id in (object["likes"] || []) bookmarked = opts[:for] && object["id"] in opts[:for].bookmarks @@ -203,7 +207,7 @@ def render("status.json", %{activity: %{data: %{"object" => object}} = activity} reblogs_count: announcement_count, replies_count: object["repliesCount"] || 0, favourites_count: like_count, - reblogged: present?(repeated), + reblogged: reblogged?(activity, opts[:for]), favourited: present?(favorited), bookmarked: present?(bookmarked), muted: CommonAPI.thread_muted?(user, activity) || User.mutes?(opts[:for], user), diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index 292cd46b8..86c411f24 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -1008,8 +1008,41 @@ test "reblogs and returns the reblogged status", %{conn: conn} do |> assign(:user, user) |> post("/api/v1/statuses/#{activity.id}/reblog") - assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} = - json_response(conn, 200) + assert %{ + "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}, + "reblogged" => true + } = json_response(conn, 200) + + assert to_string(activity.id) == id + end + + test "reblogged status for another user", %{conn: conn} do + activity = insert(:note_activity) + user1 = insert(:user) + user2 = insert(:user) + user3 = insert(:user) + {:ok, reblog_activity1, _object} = CommonAPI.repeat(activity.id, user1) + {:ok, _, _object} = CommonAPI.repeat(activity.id, user2) + + conn_res = + conn + |> assign(:user, user3) + |> get("/api/v1/statuses/#{reblog_activity1.id}") + + assert %{ + "reblog" => %{"id" => id, "reblogged" => false, "reblogs_count" => 2}, + "reblogged" => false + } = json_response(conn_res, 200) + + conn_res = + conn + |> assign(:user, user2) + |> get("/api/v1/statuses/#{reblog_activity1.id}") + + assert %{ + "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 2}, + "reblogged" => true + } = json_response(conn_res, 200) assert to_string(activity.id) == id end From ec42b639a347903ea5c0e5f9b365f1d5ea9e624f Mon Sep 17 00:00:00 2001 From: Sadposter Date: Sun, 14 Apr 2019 15:46:54 +0100 Subject: [PATCH 05/23] fix pattern match on user registration deliver_async will return a single atom --- lib/pleroma/user.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 4a41a15c7..3ab7bd742 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -270,7 +270,7 @@ def register(%Ecto.Changeset{} = changeset) do with {:ok, user} <- Repo.insert(changeset), {:ok, user} <- autofollow_users(user), {:ok, _} <- Pleroma.User.WelcomeMessage.post_welcome_message_to_user(user), - {:ok, _} <- try_send_confirmation_email(user) do + :ok <- try_send_confirmation_email(user) do {:ok, user} end end From 5e4555775189ef8c40968769a90602cb10fd5324 Mon Sep 17 00:00:00 2001 From: Sadposter Date: Sun, 14 Apr 2019 16:01:48 +0100 Subject: [PATCH 06/23] Always return {atom, _} from try_send_confirmation --- lib/pleroma/user.ex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 3ab7bd742..78eb29ddd 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -270,7 +270,7 @@ def register(%Ecto.Changeset{} = changeset) do with {:ok, user} <- Repo.insert(changeset), {:ok, user} <- autofollow_users(user), {:ok, _} <- Pleroma.User.WelcomeMessage.post_welcome_message_to_user(user), - :ok <- try_send_confirmation_email(user) do + {:ok, _} <- try_send_confirmation_email(user) do {:ok, user} end end @@ -281,6 +281,8 @@ def try_send_confirmation_email(%User{} = user) do user |> Pleroma.Emails.UserEmail.account_confirmation_email() |> Pleroma.Emails.Mailer.deliver_async() + + {:ok, :enqueued} else {:ok, :noop} end From 16d8c8b33b654b88e5e934832d5e26eb7152633e Mon Sep 17 00:00:00 2001 From: Sadposter Date: Sun, 14 Apr 2019 16:05:26 +0100 Subject: [PATCH 07/23] Assert on the success of enqueue before returning --- lib/pleroma/user.ex | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 78eb29ddd..f3ea5289e 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -278,9 +278,10 @@ def register(%Ecto.Changeset{} = changeset) do def try_send_confirmation_email(%User{} = user) do if user.info.confirmation_pending && Pleroma.Config.get([:instance, :account_activation_required]) do - user - |> Pleroma.Emails.UserEmail.account_confirmation_email() - |> Pleroma.Emails.Mailer.deliver_async() + :ok = + user + |> Pleroma.Emails.UserEmail.account_confirmation_email() + |> Pleroma.Emails.Mailer.deliver_async() {:ok, :enqueued} else From e513504e8840f5a64ae4ba795b158a102e4e8843 Mon Sep 17 00:00:00 2001 From: Sadposter Date: Sun, 14 Apr 2019 16:12:54 +0100 Subject: [PATCH 08/23] Revert "Assert on the success of enqueue before returning" This reverts commit 16d8c8b33b654b88e5e934832d5e26eb7152633e. Because it breaks everything --- lib/pleroma/user.ex | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index f3ea5289e..78eb29ddd 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -278,10 +278,9 @@ def register(%Ecto.Changeset{} = changeset) do def try_send_confirmation_email(%User{} = user) do if user.info.confirmation_pending && Pleroma.Config.get([:instance, :account_activation_required]) do - :ok = - user - |> Pleroma.Emails.UserEmail.account_confirmation_email() - |> Pleroma.Emails.Mailer.deliver_async() + user + |> Pleroma.Emails.UserEmail.account_confirmation_email() + |> Pleroma.Emails.Mailer.deliver_async() {:ok, :enqueued} else From 507e7821e38fec64d149e95a28a365027e55864a Mon Sep 17 00:00:00 2001 From: eugenijm Date: Mon, 15 Apr 2019 09:44:16 +0300 Subject: [PATCH 09/23] Handle follow/unfollow directed to themselves --- .../mastodon_api/mastodon_api_controller.ex | 21 ++++++++++-- .../mastodon_api_controller_test.exs | 34 +++++++++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index e0a090659..c051d0d7b 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -815,13 +815,17 @@ def reject_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) d end def follow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do - with %User{} = followed <- User.get_by_id(id), + with {_, %User{} = followed} <- {:followed, User.get_by_id(id)}, + {_, true} <- {:followed, follower.id != followed.id}, false <- User.following?(follower, followed), {:ok, follower, followed, _} <- CommonAPI.follow(follower, followed) do conn |> put_view(AccountView) |> render("relationship.json", %{user: follower, target: followed}) else + {:followed, _} -> + {:error, :not_found} + true -> followed = User.get_cached_by_id(id) @@ -843,12 +847,16 @@ def follow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do end def follow(%{assigns: %{user: follower}} = conn, %{"uri" => uri}) do - with %User{} = followed <- User.get_by_nickname(uri), + with {_, %User{} = followed} <- {:followed, User.get_by_nickname(uri)}, + {_, true} <- {:followed, follower.id != followed.id}, {:ok, follower, followed, _} <- CommonAPI.follow(follower, followed) do conn |> put_view(AccountView) |> render("account.json", %{user: followed, for: follower}) else + {:followed, _} -> + {:error, :not_found} + {:error, message} -> conn |> put_resp_content_type("application/json") @@ -857,11 +865,18 @@ def follow(%{assigns: %{user: follower}} = conn, %{"uri" => uri}) do end def unfollow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do - with %User{} = followed <- User.get_by_id(id), + with {_, %User{} = followed} <- {:followed, User.get_by_id(id)}, + {_, true} <- {:followed, follower.id != followed.id}, {:ok, follower} <- CommonAPI.unfollow(follower, followed) do conn |> put_view(AccountView) |> render("relationship.json", %{user: follower, target: followed}) + else + {:followed, _} -> + {:error, :not_found} + + error -> + error 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 292cd46b8..ad1828ee7 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -1587,6 +1587,40 @@ test "following / unfollowing a user", %{conn: conn} do assert id == to_string(other_user.id) end + test "following / unfollowing errors" do + user = insert(:user) + + conn = + build_conn() + |> assign(:user, user) + + # self follow + conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow") + assert %{"error" => "Record not found"} = json_response(conn_res, 404) + + # self unfollow + user = User.get_by_id(user.id) + conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow") + assert %{"error" => "Record not found"} = json_response(conn_res, 404) + + # self follow via uri + user = User.get_by_id(user.id) + conn_res = post(conn, "/api/v1/follows", %{"uri" => user.nickname}) + assert %{"error" => "Record not found"} = json_response(conn_res, 404) + + # follow non existing user + conn_res = post(conn, "/api/v1/accounts/doesntexist/follow") + assert %{"error" => "Record not found"} = json_response(conn_res, 404) + + # follow non existing user via uri + conn_res = post(conn, "/api/v1/follows", %{"uri" => "doesntexist"}) + assert %{"error" => "Record not found"} = json_response(conn_res, 404) + + # unfollow non existing user + conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow") + assert %{"error" => "Record not found"} = json_response(conn_res, 404) + end + test "muting / unmuting a user", %{conn: conn} do user = insert(:user) other_user = insert(:user) From 5d73dca064df5349d2170d56da6727a52d0d44a8 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Mon, 15 Apr 2019 11:50:36 +0300 Subject: [PATCH 10/23] Remove inReplyToStatusId --- CHANGELOG.md | 1 + lib/pleroma/activity.ex | 60 ++++++++++--------- lib/pleroma/web/activity_pub/activity_pub.ex | 9 ++- .../web/activity_pub/transmogrifier.ex | 3 +- lib/pleroma/web/common_api/utils.ex | 1 - .../web/twitter_api/views/activity_view.ex | 2 +- test/activity_test.exs | 14 +++++ test/web/activity_pub/transmogrifier_test.exs | 2 - .../mastodon_api_controller_test.exs | 4 +- test/web/twitter_api/twitter_api_test.exs | 2 +- 10 files changed, 56 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf751a496..ebf21851b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Link/mention/hashtag detection is now handled by [auto_linker](https://git.pleroma.social/pleroma/auto_linker) - NodeInfo: Return `safe_dm_mentions` feature flag - Federation: Expand the audience of delete activities to all recipients of the deleted object +- Federation: Removed `inReplyToStatusId` from objects - Configuration: Dedupe enabled by default - Pleroma API: Support for emoji tags in `/api/pleroma/emoji` resulting in a breaking API change - Mastodon API: Support for `exclude_types`, `limit` and `min_id` in `/api/v1/notifications` diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index ab8861b27..e6507e5ca 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -246,20 +246,22 @@ def all_by_actor_and_id(actor, status_ids) do |> Repo.all() end - def increase_replies_count(id) do - Activity - |> where(id: ^id) - |> update([a], - set: [ - data: - fragment( - """ - jsonb_set(?, '{object, repliesCount}', - (coalesce((?->'object'->>'repliesCount')::int, 0) + 1)::varchar::jsonb, true) - """, - a.data, - a.data - ) + def increase_replies_count(nil), do: nil + + def increase_replies_count(object_ap_id) do + from(a in create_by_object_ap_id(object_ap_id), + update: [ + set: [ + data: + fragment( + """ + jsonb_set(?, '{object, repliesCount}', + (coalesce((?->'object'->>'repliesCount')::int, 0) + 1)::varchar::jsonb, true) + """, + a.data, + a.data + ) + ] ] ) |> Repo.update_all([]) @@ -269,20 +271,22 @@ def increase_replies_count(id) do end end - def decrease_replies_count(id) do - Activity - |> where(id: ^id) - |> update([a], - set: [ - data: - fragment( - """ - jsonb_set(?, '{object, repliesCount}', - (greatest(0, (?->'object'->>'repliesCount')::int - 1))::varchar::jsonb, true) - """, - a.data, - a.data - ) + def decrease_replies_count(nil), do: nil + + def decrease_replies_count(object_ap_id) do + from(a in create_by_object_ap_id(object_ap_id), + update: [ + set: [ + data: + fragment( + """ + jsonb_set(?, '{object, repliesCount}', + (greatest(0, (?->'object'->>'repliesCount')::int - 1))::varchar::jsonb, true) + """, + a.data, + a.data + ) + ] ] ) |> Repo.update_all([]) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 89fee2d9f..54dd4097c 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -91,12 +91,11 @@ def decrease_note_count_if_public(actor, object) do end def increase_replies_count_if_reply(%{ - "object" => - %{"inReplyTo" => reply_ap_id, "inReplyToStatusId" => reply_status_id} = object, + "object" => %{"inReplyTo" => reply_ap_id} = object, "type" => "Create" }) do if is_public?(object) do - Activity.increase_replies_count(reply_status_id) + Activity.increase_replies_count(reply_ap_id) Object.increase_replies_count(reply_ap_id) end end @@ -104,10 +103,10 @@ def increase_replies_count_if_reply(%{ def increase_replies_count_if_reply(_create_data), do: :noop def decrease_replies_count_if_reply(%Object{ - data: %{"inReplyTo" => reply_ap_id, "inReplyToStatusId" => reply_status_id} = object + data: %{"inReplyTo" => reply_ap_id} = object }) do if is_public?(object) do - Activity.decrease_replies_count(reply_status_id) + Activity.decrease_replies_count(reply_ap_id) Object.decrease_replies_count(reply_ap_id) end end diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 49ea73204..39cd31921 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -225,12 +225,11 @@ def fix_in_reply_to(%{"inReplyTo" => in_reply_to} = object) case fetch_obj_helper(in_reply_to_id) do {:ok, replied_object} -> - with %Activity{} = activity <- + with %Activity{} = _activity <- Activity.get_create_by_object_ap_id(replied_object.data["id"]) do object |> Map.put("inReplyTo", replied_object.data["id"]) |> Map.put("inReplyToAtomUri", object["inReplyToAtomUri"] || in_reply_to_id) - |> Map.put("inReplyToStatusId", activity.id) |> Map.put("conversation", replied_object.data["context"] || object["conversation"]) |> Map.put("context", replied_object.data["context"] || object["conversation"]) else diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 58a561a40..185292878 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -228,7 +228,6 @@ def make_note_data( if inReplyTo do object |> Map.put("inReplyTo", inReplyTo.data["object"]["id"]) - |> Map.put("inReplyToStatusId", inReplyTo.id) else object end diff --git a/lib/pleroma/web/twitter_api/views/activity_view.ex b/lib/pleroma/web/twitter_api/views/activity_view.ex index 433322eb8..ecb2b437b 100644 --- a/lib/pleroma/web/twitter_api/views/activity_view.ex +++ b/lib/pleroma/web/twitter_api/views/activity_view.ex @@ -291,7 +291,7 @@ def render( "is_local" => activity.local, "is_post_verb" => true, "created_at" => created_at, - "in_reply_to_status_id" => object["inReplyToStatusId"], + "in_reply_to_status_id" => reply_parent && reply_parent.id, "in_reply_to_screen_name" => reply_user && reply_user.nickname, "in_reply_to_profileurl" => User.profile_url(reply_user), "in_reply_to_ostatus_uri" => reply_user && reply_user.ap_id, diff --git a/test/activity_test.exs b/test/activity_test.exs index ad889f544..d8063bf11 100644 --- a/test/activity_test.exs +++ b/test/activity_test.exs @@ -28,4 +28,18 @@ test "returns the activity that created an object" do assert activity == found_activity end + + test "reply count" do + %{id: id, data: %{"object" => %{"id" => object_ap_id}}} = activity = insert(:note_activity) + + repliesCount = activity.data["object"]["repliesCount"] || 0 + expected_increase = repliesCount + 1 + Activity.increase_replies_count(object_ap_id) + %{data: %{"object" => %{"repliesCount" => actual_increase}}} = Activity.get_by_id(id) + assert expected_increase == actual_increase + expected_decrease = expected_increase - 1 + Activity.decrease_replies_count(object_ap_id) + %{data: %{"object" => %{"repliesCount" => actual_decrease}}} = Activity.get_by_id(id) + assert expected_decrease == actual_decrease + end end diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index 47cffe257..c857a7ec1 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -58,8 +58,6 @@ test "it fetches replied-to activities if we don't have them" do assert returned_activity.data["object"]["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873" - - assert returned_activity.data["object"]["inReplyToStatusId"] == activity.id end test "it works for incoming notices" do diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index 292cd46b8..df3315022 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -342,7 +342,7 @@ test "replying to a status", %{conn: conn} do activity = Activity.get_by_id(id) assert activity.data["context"] == replied_to.data["context"] - assert activity.data["object"]["inReplyToStatusId"] == replied_to.id + assert Activity.get_in_reply_to_activity(activity).id == replied_to.id end test "posting a status with an invalid in_reply_to_id", %{conn: conn} do @@ -2724,7 +2724,7 @@ test "Repeated posts that are replies incorrectly have in_reply_to_id null", %{c activity = Activity.get_by_id(id) assert activity.data["object"]["inReplyTo"] == replied_to.data["object"]["id"] - assert activity.data["object"]["inReplyToStatusId"] == replied_to.id + assert Activity.get_in_reply_to_activity(activity).id == replied_to.id # Reblog from the third user conn2 = diff --git a/test/web/twitter_api/twitter_api_test.exs b/test/web/twitter_api/twitter_api_test.exs index 6d43bd13a..8781061d4 100644 --- a/test/web/twitter_api/twitter_api_test.exs +++ b/test/web/twitter_api/twitter_api_test.exs @@ -105,7 +105,7 @@ test "create a status that is a reply" do get_in(activity.data, ["object", "context"]) assert get_in(reply.data, ["object", "inReplyTo"]) == get_in(activity.data, ["object", "id"]) - assert get_in(reply.data, ["object", "inReplyToStatusId"]) == activity.id + assert Activity.get_in_reply_to_activity(reply).id == activity.id end test "Follow another user using user_id" do From fd2e31af867379f15f1aed536cdfa779a50b812a Mon Sep 17 00:00:00 2001 From: rinpatch Date: Mon, 15 Apr 2019 11:59:01 +0300 Subject: [PATCH 11/23] oops --- test/activity_test.exs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/activity_test.exs b/test/activity_test.exs index d8063bf11..dc9c56a21 100644 --- a/test/activity_test.exs +++ b/test/activity_test.exs @@ -32,8 +32,8 @@ test "returns the activity that created an object" do test "reply count" do %{id: id, data: %{"object" => %{"id" => object_ap_id}}} = activity = insert(:note_activity) - repliesCount = activity.data["object"]["repliesCount"] || 0 - expected_increase = repliesCount + 1 + replies_count = activity.data["object"]["repliesCount"] || 0 + expected_increase = replies_count + 1 Activity.increase_replies_count(object_ap_id) %{data: %{"object" => %{"repliesCount" => actual_increase}}} = Activity.get_by_id(id) assert expected_increase == actual_increase From 27d78dc5265ea90724c698162c24290ba1b99e13 Mon Sep 17 00:00:00 2001 From: eugenijm Date: Mon, 15 Apr 2019 12:37:49 +0300 Subject: [PATCH 12/23] Use User.get_cached_by* --- lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 6 +++--- test/web/mastodon_api/mastodon_api_controller_test.exs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index c051d0d7b..63fadce38 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -815,7 +815,7 @@ def reject_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) d end def follow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do - with {_, %User{} = followed} <- {:followed, User.get_by_id(id)}, + with {_, %User{} = followed} <- {:followed, User.get_cached_by_id(id)}, {_, true} <- {:followed, follower.id != followed.id}, false <- User.following?(follower, followed), {:ok, follower, followed, _} <- CommonAPI.follow(follower, followed) do @@ -847,7 +847,7 @@ def follow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do end def follow(%{assigns: %{user: follower}} = conn, %{"uri" => uri}) do - with {_, %User{} = followed} <- {:followed, User.get_by_nickname(uri)}, + with {_, %User{} = followed} <- {:followed, User.get_cached_by_nickname(uri)}, {_, true} <- {:followed, follower.id != followed.id}, {:ok, follower, followed, _} <- CommonAPI.follow(follower, followed) do conn @@ -865,7 +865,7 @@ def follow(%{assigns: %{user: follower}} = conn, %{"uri" => uri}) do end def unfollow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do - with {_, %User{} = followed} <- {:followed, User.get_by_id(id)}, + with {_, %User{} = followed} <- {:followed, User.get_cached_by_id(id)}, {_, true} <- {:followed, follower.id != followed.id}, {:ok, follower} <- CommonAPI.unfollow(follower, followed) do conn diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index ad1828ee7..e2a96fbfa 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -1599,12 +1599,12 @@ test "following / unfollowing errors" do assert %{"error" => "Record not found"} = json_response(conn_res, 404) # self unfollow - user = User.get_by_id(user.id) + user = User.get_cached_by_id(user.id) conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow") assert %{"error" => "Record not found"} = json_response(conn_res, 404) # self follow via uri - user = User.get_by_id(user.id) + user = User.get_cached_by_id(user.id) conn_res = post(conn, "/api/v1/follows", %{"uri" => user.nickname}) assert %{"error" => "Record not found"} = json_response(conn_res, 404) From 4fecd6f9a725bc64ee84854b3c8d722a5226141f Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 15 Apr 2019 15:45:15 +0200 Subject: [PATCH 13/23] Config.exs: Add big warning so that nobody ever edits it. --- config/config.exs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/config/config.exs b/config/config.exs index 343ecbc27..eb74e7483 100644 --- a/config/config.exs +++ b/config/config.exs @@ -1,3 +1,41 @@ +# .i;;;;i. +# iYcviii;vXY: +# .YXi .i1c. +# .YC. . in7. +# .vc. ...... ;1c. +# i7, .. .;1; +# i7, .. ... .Y1i +# ,7v .6MMM@; .YX, +# .7;. ..IMMMMMM1 :t7. +# .;Y. ;$MMMMMM9. :tc. +# vY. .. .nMMM@MMU. ;1v. +# i7i ... .#MM@M@C. .....:71i +# it: .... $MMM@9;.,i;;;i,;tti +# :t7. ..... 0MMMWv.,iii:::,,;St. +# .nC. ..... IMMMQ..,::::::,.,czX. +# .ct: ....... .ZMMMI..,:::::::,,:76Y. +# c2: ......,i..Y$M@t..:::::::,,..inZY +# vov ......:ii..c$MBc..,,,,,,,,,,..iI9i +# i9Y ......iii:..7@MA,..,,,,,,,,,....;AA: +# iIS. ......:ii::..;@MI....,............;Ez. +# .I9. ......:i::::...8M1..................C0z. +# .z9; ......:i::::,.. .i:...................zWX. +# vbv ......,i::::,,. ................. :AQY +# c6Y. .,...,::::,,..:t0@@QY. ................ :8bi +# :6S. ..,,...,:::,,,..EMMMMMMI. ............... .;bZ, +# :6o, .,,,,..:::,,,..i#MMMMMM#v................. YW2. +# .n8i ..,,,,,,,::,,,,.. tMMMMM@C:.................. .1Wn +# 7Uc. .:::,,,,,::,,,,.. i1t;,..................... .UEi +# 7C...::::::::::::,,,,.. .................... vSi. +# ;1;...,,::::::,......... .................. Yz: +# v97,......... .voC. +# izAotX7777777777777777777777777777777777777777Y7n92: +# .;CoIIIIIUAA666666699999ZZZZZZZZZZZZZZZZZZZZ6ov. +# +# !!! ATTENTION !!! +# DO NOT EDIT THIS FILE! THIS FILE CONTAINS THE DEFAULT VALUES FOR THE CON- +# FIGURATION! EDIT YOUR SECRET FILE (either prod.secret.exs, dev.secret.exs). +# # This file is responsible for configuring your application # and its dependencies with the aid of the Mix.Config module. # From 088f378408e7bc9b4dd916141cba813de3276e90 Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 15 Apr 2019 15:51:17 +0200 Subject: [PATCH 14/23] Custom Emoji docs: Make it clear that config.exs is not for lewd. --- docs/config/custom_emoji.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config/custom_emoji.md b/docs/config/custom_emoji.md index 419a7d0e2..5ce9865a2 100644 --- a/docs/config/custom_emoji.md +++ b/docs/config/custom_emoji.md @@ -20,7 +20,7 @@ The files should be PNG (APNG is okay with `.png` for `image/png` Content-type) ## Emoji tags (groups) -Default tags are set in `config.exs`. +Default tags are set in `config.exs`. To set your own tags, copy the structure to your secrets file (`prod.secret.exs` or `dev.secret.exs`) and edit it. ```elixir config :pleroma, :emoji, shortcode_globs: ["/emoji/custom/**/*.png"], From 498c96d458e383a9e8b647a6f10bdbebac116579 Mon Sep 17 00:00:00 2001 From: "Dominik V. Salonen" <155-quad@users.noreply.git.pleroma.social> Date: Tue, 16 Apr 2019 07:14:44 +0000 Subject: [PATCH 15/23] Add supervisord configuration --- installation/pleroma.supervisord | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 installation/pleroma.supervisord diff --git a/installation/pleroma.supervisord b/installation/pleroma.supervisord new file mode 100644 index 000000000..19efffd6e --- /dev/null +++ b/installation/pleroma.supervisord @@ -0,0 +1,21 @@ +; Assumes pleroma is installed in /home/pleroma/pleroma and running as the pleroma user +; Also assumes mix is in /usr/bin, this might differ on BSDs or niche Linux distros +; Logs into /home/pleroma/logs +[program:pleroma] +command=/usr/bin/mix phx.server +directory=/home/pleroma/pleroma +autostart=true +autorestart=true +user=pleroma +environment = + MIX_ENV=prod, + HOME=/home/pleroma, + USER=pleroma, + PATH="/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/home/pleroma/bin:%(ENV_PATH)s", + PWD=/home/pleroma/pleroma +stdout_logfile=/home/pleroma/logs/stdout.log +stdout_logfile_maxbytes=50MB +stdout_logfile_backups=10 +stderr_logfile=/home/pleroma/logs/stderr.log +stderr_logfile_maxbytes=50MB +stderr_logfile_backups=10 \ No newline at end of file From 37da03499ea2a87e4ee2366440109eb8a514de4a Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 16 Apr 2019 14:53:17 +0300 Subject: [PATCH 16/23] Bump ex_doc --- mix.exs | 2 +- mix.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mix.exs b/mix.exs index 9531b230a..15e182239 100644 --- a/mix.exs +++ b/mix.exs @@ -90,7 +90,7 @@ defp deps do {:crypt, git: "https://github.com/msantos/crypt", ref: "1f2b58927ab57e72910191a7ebaeff984382a1d3"}, {:cors_plug, "~> 1.5"}, - {:ex_doc, "~> 0.19", only: :dev, runtime: false}, + {:ex_doc, "~> 0.20.2", only: :dev, runtime: false}, {:web_push_encryption, "~> 0.2.1"}, {:swoosh, "~> 0.20"}, {:gen_smtp, "~> 0.13"}, diff --git a/mix.lock b/mix.lock index e13fdcbd4..d494cc82d 100644 --- a/mix.lock +++ b/mix.lock @@ -16,13 +16,13 @@ "crypt": {:git, "https://github.com/msantos/crypt", "1f2b58927ab57e72910191a7ebaeff984382a1d3", [ref: "1f2b58927ab57e72910191a7ebaeff984382a1d3"]}, "db_connection": {:hex, :db_connection, "2.0.5", "ddb2ba6761a08b2bb9ca0e7d260e8f4dd39067426d835c24491a321b7f92a4da", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm"}, "decimal": {:hex, :decimal, "1.7.0", "30d6b52c88541f9a66637359ddf85016df9eb266170d53105f02e4a67e00c5aa", [:mix], [], "hexpm"}, - "earmark": {:hex, :earmark, "1.3.0", "17f0c38eaafb4800f746b457313af4b2442a8c2405b49c645768680f900be603", [:mix], [], "hexpm"}, + "earmark": {:hex, :earmark, "1.3.2", "b840562ea3d67795ffbb5bd88940b1bed0ed9fa32834915125ea7d02e35888a5", [:mix], [], "hexpm"}, "ecto": {:hex, :ecto, "3.0.7", "44dda84ac6b17bbbdeb8ac5dfef08b7da253b37a453c34ab1a98de7f7e5fec7f", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}], "hexpm"}, "ecto_sql": {:hex, :ecto_sql, "3.0.5", "7e44172b4f7aca4469f38d7f6a3da394dbf43a1bcf0ca975e958cb957becd74e", [:mix], [{:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.0.6", [hex: :ecto, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.9.1", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.14.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.3.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"}, "eternal": {:hex, :eternal, "1.2.0", "e2a6b6ce3b8c248f7dc31451aefca57e3bdf0e48d73ae5043229380a67614c41", [:mix], [], "hexpm"}, "ex_aws": {:hex, :ex_aws, "2.1.0", "b92651527d6c09c479f9013caa9c7331f19cba38a650590d82ebf2c6c16a1d8a", [:mix], [{:configparser_ex, "~> 2.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "1.6.3 or 1.6.5 or 1.7.1 or 1.8.6 or ~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8", [hex: :jsx, repo: "hexpm", optional: true]}, {:poison, ">= 1.2.0", [hex: :poison, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:xml_builder, "~> 0.1.0", [hex: :xml_builder, repo: "hexpm", optional: true]}], "hexpm"}, "ex_aws_s3": {:hex, :ex_aws_s3, "2.0.1", "9e09366e77f25d3d88c5393824e613344631be8db0d1839faca49686e99b6704", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm"}, - "ex_doc": {:hex, :ex_doc, "0.19.1", "519bb9c19526ca51d326c060cb1778d4a9056b190086a8c6c115828eaccea6cf", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.7", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"}, + "ex_doc": {:hex, :ex_doc, "0.20.2", "1bd0dfb0304bade58beb77f20f21ee3558cc3c753743ae0ddbb0fd7ba2912331", [:mix], [{:earmark, "~> 1.3", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.10", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"}, "ex_machina": {:hex, :ex_machina, "2.3.0", "92a5ad0a8b10ea6314b876a99c8c9e3f25f4dde71a2a835845b136b9adaf199a", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm"}, "ex_syslogger": {:git, "https://github.com/slashmili/ex_syslogger.git", "f3963399047af17e038897c69e20d552e6899e1d", [tag: "1.4.0"]}, "floki": {:hex, :floki, "0.20.4", "be42ac911fece24b4c72f3b5846774b6e61b83fe685c2fc9d62093277fb3bc86", [:mix], [{:html_entities, "~> 0.4.0", [hex: :html_entities, repo: "hexpm", optional: false]}, {:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm"}, @@ -35,8 +35,8 @@ "idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"}, "jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"}, "jose": {:hex, :jose, "1.8.4", "7946d1e5c03a76ac9ef42a6e6a20001d35987afd68c2107bcd8f01a84e75aa73", [:mix, :rebar3], [{:base64url, "~> 0.0.1", [hex: :base64url, repo: "hexpm", optional: false]}], "hexpm"}, - "makeup": {:hex, :makeup, "0.5.5", "9e08dfc45280c5684d771ad58159f718a7b5788596099bdfb0284597d368a882", [:mix], [{:nimble_parsec, "~> 0.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"}, - "makeup_elixir": {:hex, :makeup_elixir, "0.10.0", "0f09c2ddf352887a956d84f8f7e702111122ca32fbbc84c2f0569b8b65cbf7fa", [:mix], [{:makeup, "~> 0.5.5", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"}, + "makeup": {:hex, :makeup, "0.8.0", "9cf32aea71c7fe0a4b2e9246c2c4978f9070257e5c9ce6d4a28ec450a839b55f", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"}, + "makeup_elixir": {:hex, :makeup_elixir, "0.13.0", "be7a477997dcac2e48a9d695ec730b2d22418292675c75aa2d34ba0909dcdeda", [:mix], [{:makeup, "~> 0.8", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"}, "meck": {:hex, :meck, "0.8.13", "ffedb39f99b0b99703b8601c6f17c7f76313ee12de6b646e671e3188401f7866", [:rebar3], [], "hexpm"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"}, "mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm"}, @@ -44,7 +44,7 @@ "mochiweb": {:hex, :mochiweb, "2.15.0", "e1daac474df07651e5d17cc1e642c4069c7850dc4508d3db7263a0651330aacc", [:rebar3], [], "hexpm"}, "mock": {:hex, :mock, "0.3.1", "994f00150f79a0ea50dc9d86134cd9ebd0d177ad60bd04d1e46336cdfdb98ff9", [:mix], [{:meck, "~> 0.8.8", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"}, "mogrify": {:hex, :mogrify, "0.6.1", "de1b527514f2d95a7bbe9642eb556061afb337e220cf97adbf3a4e6438ed70af", [:mix], [], "hexpm"}, - "nimble_parsec": {:hex, :nimble_parsec, "0.4.0", "ee261bb53214943679422be70f1658fff573c5d0b0a1ecd0f18738944f818efe", [:mix], [], "hexpm"}, + "nimble_parsec": {:hex, :nimble_parsec, "0.5.0", "90e2eca3d0266e5c53f8fbe0079694740b9c91b6747f2b7e3c5d21966bba8300", [:mix], [], "hexpm"}, "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"}, "pbkdf2_elixir": {:hex, :pbkdf2_elixir, "0.12.3", "6706a148809a29c306062862c803406e88f048277f6e85b68faf73291e820b84", [:mix], [], "hexpm"}, "phoenix": {:hex, :phoenix, "1.4.1", "801f9d632808657f1f7c657c8bbe624caaf2ba91429123ebe3801598aea4c3d9", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm"}, From 10096bbf2b6c18104cb63b5486681d00eaa5fb6c Mon Sep 17 00:00:00 2001 From: Hakurei Reimu Date: Mon, 15 Apr 2019 12:31:37 +0800 Subject: [PATCH 17/23] add extra_cookie_attrs option to config Allow instance admins to set their own SameSite cookie policy from the config. Default value in the config is `Lax`. --- config/config.exs | 5 ++++- docs/config.md | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/config/config.exs b/config/config.exs index eb74e7483..750e593e3 100644 --- a/config/config.exs +++ b/config/config.exs @@ -154,7 +154,10 @@ signing_salt: "CqaoopA2", render_errors: [view: Pleroma.Web.ErrorView, accepts: ~w(json)], pubsub: [name: Pleroma.PubSub, adapter: Phoenix.PubSub.PG2], - secure_cookie_flag: true + secure_cookie_flag: true, + extra_cookie_attrs: [ + "SameSite=Lax" + ] # Configures Elixir's Logger config :logger, :console, diff --git a/docs/config.md b/docs/config.md index e286104df..117fda960 100644 --- a/docs/config.md +++ b/docs/config.md @@ -221,6 +221,8 @@ This section is used to configure Pleroma-FE, unless ``:managed_config`` in ``:i - `scheme` - e.g `http`, `https` - `port` - `path` +* `extra_cookie_attrs` - a list of `Key=Value` strings to be added as non-standard cookie attributes. Defaults to `["SameSite=Lax"]`. See the [SameSite article](https://www.owasp.org/index.php/SameSite) on OWASP for more info. + **Important note**: if you modify anything inside these lists, default `config.exs` values will be overwritten, which may result in breakage, to make sure this does not happen please copy the default value for the list from `config.exs` and modify/add only what you need @@ -442,6 +444,8 @@ The server should also be started with `OAUTH_CONSUMER_STRATEGIES="..." mix phx. Note: each strategy requires separate setup (on external provider side and Pleroma side). Below are the guidelines on setting up most popular strategies. +Note: make sure that `"SameSite=Lax"` is set in `extra_cookie_attrs` when you have this feature enabled. OAuth consumer mode will not work with `"SameSite=Strict"` + * For Twitter, [register an app](https://developer.twitter.com/en/apps), configure callback URL to https:///oauth/twitter/callback * For Facebook, [register an app](https://developers.facebook.com/apps), configure callback URL to https:///oauth/facebook/callback, enable Facebook Login service at https://developers.facebook.com/apps//fb-login/settings/ From 6e26ac10a36354c2a08ccddd0fd2df658aba5e4b Mon Sep 17 00:00:00 2001 From: Hakurei Reimu Date: Mon, 15 Apr 2019 12:33:46 +0800 Subject: [PATCH 18/23] make Pleroma.Endpoint use extra_cookie_attrs in config --- lib/pleroma/web/endpoint.ex | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex index 1633477c3..7f939991d 100644 --- a/lib/pleroma/web/endpoint.ex +++ b/lib/pleroma/web/endpoint.ex @@ -58,14 +58,9 @@ defmodule Pleroma.Web.Endpoint do do: "__Host-pleroma_key", else: "pleroma_key" - same_site = - if Pleroma.Config.oauth_consumer_enabled?() do - # Note: "SameSite=Strict" prevents sign in with external OAuth provider - # (there would be no cookies during callback request from OAuth provider) - "SameSite=Lax" - else - "SameSite=Strict" - end + extra = + Pleroma.Config.get([__MODULE__, :extra_cookie_attrs]) + |> Enum.join(";") # The session will be stored in the cookie and signed, # this means its contents can be read but not tampered with. @@ -77,7 +72,7 @@ defmodule Pleroma.Web.Endpoint do signing_salt: {Pleroma.Config, :get, [[__MODULE__, :signing_salt], "CqaoopA2"]}, http_only: true, secure: secure_cookies, - extra: same_site + extra: extra ) # Note: the plug and its configuration is compile-time this can't be upstreamed yet From 2472efb4e9aafe68d1ab3eef12ea3c3ad3859029 Mon Sep 17 00:00:00 2001 From: Hakurei Reimu Date: Tue, 16 Apr 2019 22:24:24 +0800 Subject: [PATCH 19/23] Add extra_cookie_attrs to changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ebf21851b..1d2ad3320 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Federation: Expand the audience of delete activities to all recipients of the deleted object - Federation: Removed `inReplyToStatusId` from objects - Configuration: Dedupe enabled by default +- Configuration: Added `extra_cookie_attrs` for setting non-standard cookie attributes. Defaults to ["SameSite=Lax"] so that remote follows work. - Pleroma API: Support for emoji tags in `/api/pleroma/emoji` resulting in a breaking API change - Mastodon API: Support for `exclude_types`, `limit` and `min_id` in `/api/v1/notifications` - Mastodon API: Add `languages` and `registrations` to `/api/v1/instance` From 750b369d0469ba7ec037ff953e65473e32d7fa33 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Tue, 16 Apr 2019 18:10:15 +0000 Subject: [PATCH 20/23] activitypub: allow indirect messages from users being followed at a personal inbox --- .../activity_pub/activity_pub_controller.ex | 7 +++-- lib/pleroma/web/activity_pub/utils.ex | 7 ++++- .../activity_pub_controller_test.exs | 30 +++++++++++++++++++ 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index 7091d6927..3331ebebd 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -153,9 +153,10 @@ def outbox(conn, %{"nickname" => nickname} = params) do end def inbox(%{assigns: %{valid_signature: true}} = conn, %{"nickname" => nickname} = params) do - with %User{} = user <- User.get_cached_by_nickname(nickname), - true <- Utils.recipient_in_message(user.ap_id, params), - params <- Utils.maybe_splice_recipient(user.ap_id, params) do + with %User{} = recipient <- User.get_cached_by_nickname(nickname), + %User{} = actor <- User.get_or_fetch_by_ap_id(params["actor"]), + true <- Utils.recipient_in_message(recipient, actor, params), + params <- Utils.maybe_splice_recipient(recipient.ap_id, params) do Federator.incoming_ap_doc(params) json(conn, "ok") end diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 0b53f71c3..ccc9da7c6 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -52,7 +52,7 @@ defp recipient_in_collection(ap_id, coll) when is_binary(coll), do: ap_id == col defp recipient_in_collection(ap_id, coll) when is_list(coll), do: ap_id in coll defp recipient_in_collection(_, _), do: false - def recipient_in_message(ap_id, params) do + def recipient_in_message(%User{ap_id: ap_id} = recipient, %User{} = actor, params) do cond do recipient_in_collection(ap_id, params["to"]) -> true @@ -71,6 +71,11 @@ def recipient_in_message(ap_id, params) do !params["to"] && !params["cc"] && !params["bto"] && !params["bcc"] -> true + # if the message is sent from somebody the user is following, then assume it + # is addressed to the recipient + User.following?(recipient, actor) -> + true + true -> false end diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs index 8dd8e7e0a..7b1c60f15 100644 --- a/test/web/activity_pub/activity_pub_controller_test.exs +++ b/test/web/activity_pub/activity_pub_controller_test.exs @@ -253,6 +253,36 @@ test "it inserts an incoming activity into the database", %{conn: conn} do assert Activity.get_by_ap_id(data["id"]) end + test "it accepts messages from actors that are followed by the user", %{conn: conn} do + recipient = insert(:user) + actor = insert(:user, %{ap_id: "http://mastodon.example.org/users/actor"}) + + {:ok, recipient} = User.follow(recipient, actor) + + data = + File.read!("test/fixtures/mastodon-post-activity.json") + |> Poison.decode!() + + object = + data["object"] + |> Map.put("attributedTo", actor.ap_id) + + data = + data + |> Map.put("actor", actor.ap_id) + |> Map.put("object", object) + + conn = + conn + |> assign(:valid_signature, true) + |> put_req_header("content-type", "application/activity+json") + |> post("/users/#{recipient.nickname}/inbox", data) + + assert "ok" == json_response(conn, 200) + :timer.sleep(500) + assert Activity.get_by_ap_id(data["id"]) + end + test "it rejects reads from other users", %{conn: conn} do user = insert(:user) otheruser = insert(:user) From d4a749cfb2f644dab9b0f414e8f0e41ed4ffd08f Mon Sep 17 00:00:00 2001 From: Normandy Date: Tue, 16 Apr 2019 18:35:38 +0000 Subject: [PATCH 21/23] Handle new-style mastodon follow lists Fixes https://git.pleroma.social/pleroma/pleroma/issues/814 --- .../twitter_api/controllers/util_controller.ex | 7 ++++++- test/web/twitter_api/util_controller_test.exs | 15 +++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index d066d35f5..ed45ca735 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -304,7 +304,12 @@ def follow_import(conn, %{"list" => %Plug.Upload{} = listfile}) do end def follow_import(%{assigns: %{user: follower}} = conn, %{"list" => list}) do - with followed_identifiers <- String.split(list), + with lines <- String.split(list, "\n"), + followed_identifiers <- + Enum.map(lines, fn line -> + String.split(line, ",") |> List.first() + end) + |> List.delete("Account address"), {:ok, _} = Task.start(fn -> User.follow_import(follower, followed_identifiers) end) do json(conn, "job started") end diff --git a/test/web/twitter_api/util_controller_test.exs b/test/web/twitter_api/util_controller_test.exs index a4b3d651a..c58b49ea4 100644 --- a/test/web/twitter_api/util_controller_test.exs +++ b/test/web/twitter_api/util_controller_test.exs @@ -26,6 +26,21 @@ test "it returns HTTP 200", %{conn: conn} do assert response == "job started" end + test "it imports new-style mastodon follow lists", %{conn: conn} do + user1 = insert(:user) + user2 = insert(:user) + + response = + conn + |> assign(:user, user1) + |> post("/api/pleroma/follow_import", %{ + "list" => "Account address,Show boosts\n#{user2.ap_id},true" + }) + |> json_response(:ok) + + 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"]) From 6ac948c5b89ca6ea0c1adbd45a408a6a1db227ae Mon Sep 17 00:00:00 2001 From: Alex S Date: Wed, 17 Apr 2019 14:12:45 +0700 Subject: [PATCH 22/23] changelog info --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d2ad3320..b9e4e93d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Mastodon API: `/api/v1/notifications/destroy_multiple` (glitch-soc extension) - Mastodon API: [Reports](https://docs.joinmastodon.org/api/rest/reports/) - ActivityPub C2S: OAuth endpoints +- Email address, which is used for notifications. Instance configuration: `notify_email` ### Changed - **Breaking:** Configuration: move from Pleroma.Mailer to Pleroma.Emails.Mailer From 2198e54d28f1e1c5a2f2d39426f1bdcc97c00213 Mon Sep 17 00:00:00 2001 From: Alex S Date: Wed, 17 Apr 2019 14:27:51 +0700 Subject: [PATCH 23/23] changes --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b9e4e93d3..21ad83a01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Configuration: `safe_dm_mentions` option - Configuration: `link_name` option - Configuration: `fetch_initial_posts` option +- Configuration: `notify_email` option - Pleroma API: User subscribtions - Admin API: Endpoints for listing/revoking invite tokens - Admin API: Endpoints for making users follow/unfollow each other @@ -21,7 +22,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Mastodon API: `/api/v1/notifications/destroy_multiple` (glitch-soc extension) - Mastodon API: [Reports](https://docs.joinmastodon.org/api/rest/reports/) - ActivityPub C2S: OAuth endpoints -- Email address, which is used for notifications. Instance configuration: `notify_email` ### Changed - **Breaking:** Configuration: move from Pleroma.Mailer to Pleroma.Emails.Mailer