Verify link ownership with rel="me"

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak 2022-11-20 23:19:52 +01:00
parent e3ea311cd5
commit 50e7706b26
5 changed files with 105 additions and 9 deletions

View File

@ -0,0 +1 @@
Verify profile link ownership with rel="me"

View File

@ -8,6 +8,7 @@ defmodule Pleroma.User do
import Ecto.Changeset import Ecto.Changeset
import Ecto.Query import Ecto.Query
import Ecto, only: [assoc: 2] import Ecto, only: [assoc: 2]
import Pleroma.Web.Utils.Guards, only: [not_empty_string: 1]
alias Ecto.Multi alias Ecto.Multi
alias Pleroma.Activity alias Pleroma.Activity
@ -595,9 +596,23 @@ defmodule Pleroma.User do
defp put_fields(changeset) do defp put_fields(changeset) do
if raw_fields = get_change(changeset, :raw_fields) do if raw_fields = get_change(changeset, :raw_fields) do
old_fields = changeset.data.raw_fields
raw_fields = raw_fields =
raw_fields raw_fields
|> Enum.filter(fn %{"name" => n} -> n != "" end) |> Enum.filter(fn %{"name" => n} -> n != "" end)
|> Enum.map(fn field ->
previous =
old_fields
|> Enum.find(fn %{"value" => value} -> field["value"] == value end)
if previous && Map.has_key?(previous, "verified_at") do
field
|> Map.put("verified_at", previous["verified_at"])
else
field
end
end)
fields = fields =
raw_fields raw_fields
@ -1198,6 +1213,10 @@ defmodule Pleroma.User do
def update_and_set_cache(changeset) do def update_and_set_cache(changeset) do
with {:ok, user} <- Repo.update(changeset, stale_error_field: :id) do with {:ok, user} <- Repo.update(changeset, stale_error_field: :id) do
if get_change(changeset, :raw_fields) do
BackgroundWorker.enqueue("verify_fields_links", %{"user_id" => user.id})
end
set_cache(user) set_cache(user)
end end
end end
@ -1970,8 +1989,47 @@ defmodule Pleroma.User do
maybe_delete_from_db(user) maybe_delete_from_db(user)
end end
def perform(:verify_fields_links, user) do
profile_urls = [user.ap_id]
fields =
user.raw_fields
|> Enum.map(&verify_field_link(&1, profile_urls))
changeset =
user
|> update_changeset(%{raw_fields: fields})
with {:ok, user} <- Repo.update(changeset, stale_error_field: :id) do
set_cache(user)
end
end
def perform(:set_activation_async, user, status), do: set_activation(user, status) def perform(:set_activation_async, user, status), do: set_activation(user, status)
defp verify_field_link(field, profile_urls) do
verified_at =
with %{"value" => value} <- field,
{:verified_at, nil} <- {:verified_at, Map.get(field, "verified_at")},
%{scheme: scheme, userinfo: nil, host: host}
when not_empty_string(host) and scheme in ["http", "https"] <-
URI.parse(value),
{:not_idn, true} <- {:not_idn, to_string(:idna.encode(host)) == host},
attr <- Pleroma.Web.RelMe.maybe_put_rel_me(value, profile_urls) do
if attr == "me" do
CommonUtils.to_masto_date(NaiveDateTime.utc_now())
end
else
{:verified_at, value} when not_empty_string(value) ->
value
_ ->
nil
end
Map.put(field, "verified_at", verified_at)
end
@spec external_users_query() :: Ecto.Query.t() @spec external_users_query() :: Ecto.Query.t()
def external_users_query do def external_users_query do
User.Query.build(%{ User.Query.build(%{
@ -2659,10 +2717,11 @@ defmodule Pleroma.User do
# - display name # - display name
def sanitize_html(%User{} = user, filter) do def sanitize_html(%User{} = user, filter) do
fields = fields =
Enum.map(user.fields, fn %{"name" => name, "value" => value} -> Enum.map(user.fields, fn %{"name" => name, "value" => value} = fields ->
%{ %{
"name" => name, "name" => name,
"value" => HTML.filter_tags(value, Pleroma.HTML.Scrubber.LinksOnly) "value" => HTML.filter_tags(value, Pleroma.HTML.Scrubber.LinksOnly),
"verified_at" => Map.get(fields, "verified_at")
} }
end) end)

View File

@ -40,6 +40,11 @@ defmodule Pleroma.Workers.BackgroundWorker do
Pleroma.FollowingRelationship.move_following(origin, target) Pleroma.FollowingRelationship.move_following(origin, target)
end end
def perform(%Job{args: %{"op" => "verify_fields_links", "user_id" => user_id}}) do
user = User.get_by_id(user_id)
User.perform(:verify_fields_links, user)
end
def perform(%Job{args: %{"op" => "delete_instance", "host" => host}}) do def perform(%Job{args: %{"op" => "delete_instance", "host" => host}}) do
Instance.perform(:delete_instance, host) Instance.perform(:delete_instance, host)
end end

View File

@ -2913,4 +2913,29 @@ defmodule Pleroma.UserTest do
refute User.endorses?(user, pinned_user) refute User.endorses?(user, pinned_user)
end end
end end
test "it checks fields links for a backlink" do
user = insert(:user, ap_id: "https://social.example.org/users/lain")
fields = [
%{"name" => "Link", "value" => "http://example.com/rel_me/null"},
%{"name" => "Verified link", "value" => "http://example.com/rel_me/link"},
%{"name" => "Not a link", "value" => "i'm not a link"}
]
user
|> User.update_and_set_cache(%{raw_fields: fields})
ObanHelpers.perform_all()
user = User.get_cached_by_id(user.id)
assert [
%{"verified_at" => nil},
%{"verified_at" => verified_at},
%{"verified_at" => nil}
] = user.fields
assert is_binary(verified_at)
end
end end

View File

@ -502,10 +502,15 @@ defmodule Pleroma.Web.MastodonAPI.UpdateCredentialsTest do
|> json_response_and_validate_schema(200) |> json_response_and_validate_schema(200)
assert account_data["fields"] == [ assert account_data["fields"] == [
%{"name" => "<a href=\"http://google.com\">foo</a>", "value" => "bar"}, %{
"name" => "<a href=\"http://google.com\">foo</a>",
"value" => "bar",
"verified_at" => nil
},
%{ %{
"name" => "link.io", "name" => "link.io",
"value" => ~S(<a href="http://cofe.io" rel="ugc">cofe.io</a>) "value" => ~S(<a href="http://cofe.io" rel="ugc">cofe.io</a>),
"verified_at" => nil
} }
] ]
@ -564,8 +569,8 @@ defmodule Pleroma.Web.MastodonAPI.UpdateCredentialsTest do
|> json_response_and_validate_schema(200) |> json_response_and_validate_schema(200)
assert account_data["fields"] == [ assert account_data["fields"] == [
%{"name" => ":firefox:", "value" => "is best 2hu"}, %{"name" => ":firefox:", "value" => "is best 2hu", "verified_at" => nil},
%{"name" => "they wins", "value" => ":blank:"} %{"name" => "they wins", "value" => ":blank:", "verified_at" => nil}
] ]
assert account_data["source"]["fields"] == [ assert account_data["source"]["fields"] == [
@ -593,10 +598,11 @@ defmodule Pleroma.Web.MastodonAPI.UpdateCredentialsTest do
|> json_response_and_validate_schema(200) |> json_response_and_validate_schema(200)
assert account["fields"] == [ assert account["fields"] == [
%{"name" => "foo", "value" => "bar"}, %{"name" => "foo", "value" => "bar", "verified_at" => nil},
%{ %{
"name" => "link", "name" => "link",
"value" => ~S(<a href="http://cofe.io" rel="ugc">http://cofe.io</a>) "value" => ~S(<a href="http://cofe.io" rel="ugc">http://cofe.io</a>),
"verified_at" => nil
} }
] ]
@ -618,7 +624,7 @@ defmodule Pleroma.Web.MastodonAPI.UpdateCredentialsTest do
|> json_response_and_validate_schema(200) |> json_response_and_validate_schema(200)
assert account["fields"] == [ assert account["fields"] == [
%{"name" => "foo", "value" => ""} %{"name" => "foo", "value" => "", "verified_at" => nil}
] ]
end end