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 4f61f19f56
commit b001a2c2c8
3 changed files with 85 additions and 0 deletions

View file

@ -8,6 +8,7 @@ defmodule Pleroma.User do
import Ecto.Changeset
import Ecto.Query
import Ecto, only: [assoc: 2]
import Pleroma.Web.Utils.Guards, only: [not_empty_string: 1]
alias Ecto.Multi
alias Pleroma.Activity
@ -573,9 +574,23 @@ def update_changeset(struct, params \\ %{}) do
defp put_fields(changeset) do
if raw_fields = get_change(changeset, :raw_fields) do
old_fields = changeset.data.raw_fields
raw_fields =
raw_fields
|> 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 =
raw_fields
@ -1176,6 +1191,7 @@ def update_and_set_cache(%{data: %Pleroma.User{} = user} = changeset) do
with {:ok, user} <- Repo.update(changeset, stale_error_field: :id) do
set_cache(user)
BackgroundWorker.enqueue("verify_fields_links", %{"user_id" => user.id})
end
|> maybe_remove_report_notifications(was_superuser_before_update)
end
@ -1967,8 +1983,47 @@ def perform(:delete, %User{} = user) do
maybe_delete_from_db(user)
end
def perform(:verify_fields_links, user) do
profile_urls = [user.ap_id, "#{Endpoint.url()}/@#{user.nickname}"]
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)
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()
def external_users_query do
User.Query.build(%{

View file

@ -40,6 +40,11 @@ def perform(%Job{
Pleroma.FollowingRelationship.move_following(origin, target)
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
Instance.perform(:delete_instance, host)
end

View file

@ -2849,4 +2849,29 @@ test "it doesn't pin users you do not follow" do
refute User.endorses?(user, pinned_user)
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