Improve group refreshment and fixed date signature generation
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
parent
6d599441a9
commit
55af776df9
|
@ -90,6 +90,8 @@ config :mobilizon, Mobilizon.Web.Upload.Uploader.Local, uploads: "/var/lib/mobil
|
||||||
|
|
||||||
config :tz_world, data_dir: "/var/lib/mobilizon/timezones"
|
config :tz_world, data_dir: "/var/lib/mobilizon/timezones"
|
||||||
|
|
||||||
|
config :mobilizon, Timex.Gettext, default_locale: "en"
|
||||||
|
|
||||||
config :mobilizon, :media_proxy,
|
config :mobilizon, :media_proxy,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
proxy_opts: [
|
proxy_opts: [
|
||||||
|
|
|
@ -32,14 +32,14 @@ defmodule Mobilizon.Federation.ActivityPub.Actor do
|
||||||
case Actors.get_actor_by_url(url, preload) do
|
case Actors.get_actor_by_url(url, preload) do
|
||||||
{:ok, %Actor{} = cached_actor} ->
|
{:ok, %Actor{} = cached_actor} ->
|
||||||
if Actors.needs_update?(cached_actor) do
|
if Actors.needs_update?(cached_actor) do
|
||||||
__MODULE__.make_actor_from_url(url, preload)
|
__MODULE__.make_actor_from_url(url, preload: preload)
|
||||||
else
|
else
|
||||||
{:ok, cached_actor}
|
{:ok, cached_actor}
|
||||||
end
|
end
|
||||||
|
|
||||||
{:error, :actor_not_found} ->
|
{:error, :actor_not_found} ->
|
||||||
# For tests, see https://github.com/jjh42/mock#not-supported---mocking-internal-function-calls and Mobilizon.Federation.ActivityPubTest
|
# For tests, see https://github.com/jjh42/mock#not-supported---mocking-internal-function-calls and Mobilizon.Federation.ActivityPubTest
|
||||||
__MODULE__.make_actor_from_url(url, preload)
|
__MODULE__.make_actor_from_url(url, preload: preload)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -48,15 +48,15 @@ defmodule Mobilizon.Federation.ActivityPub.Actor do
|
||||||
@doc """
|
@doc """
|
||||||
Create an actor locally by its URL (AP ID)
|
Create an actor locally by its URL (AP ID)
|
||||||
"""
|
"""
|
||||||
@spec make_actor_from_url(url :: String.t(), preload :: boolean()) ::
|
@spec make_actor_from_url(url :: String.t(), options :: Keyword.t()) ::
|
||||||
{:ok, Actor.t()} | {:error, make_actor_errors | Ecto.Changeset.t()}
|
{:ok, Actor.t()} | {:error, make_actor_errors | Ecto.Changeset.t()}
|
||||||
def make_actor_from_url(url, preload \\ false) do
|
def make_actor_from_url(url, options \\ []) do
|
||||||
if are_same_origin?(url, Endpoint.url()) do
|
if are_same_origin?(url, Endpoint.url()) do
|
||||||
{:error, :actor_is_local}
|
{:error, :actor_is_local}
|
||||||
else
|
else
|
||||||
case Fetcher.fetch_and_prepare_actor_from_url(url) do
|
case Fetcher.fetch_and_prepare_actor_from_url(url, options) do
|
||||||
{:ok, data} when is_map(data) ->
|
{:ok, data} when is_map(data) ->
|
||||||
Actors.upsert_actor(data, preload)
|
Actors.upsert_actor(data, Keyword.get(options, :preload, false))
|
||||||
|
|
||||||
# Request returned 410
|
# Request returned 410
|
||||||
{:error, :actor_deleted} ->
|
{:error, :actor_deleted} ->
|
||||||
|
@ -78,13 +78,13 @@ defmodule Mobilizon.Federation.ActivityPub.Actor do
|
||||||
case Actors.get_actor_by_name_with_preload(nickname, type) do
|
case Actors.get_actor_by_name_with_preload(nickname, type) do
|
||||||
%Actor{url: actor_url} = actor ->
|
%Actor{url: actor_url} = actor ->
|
||||||
if Actors.needs_update?(actor) do
|
if Actors.needs_update?(actor) do
|
||||||
make_actor_from_url(actor_url, true)
|
make_actor_from_url(actor_url, preload: true)
|
||||||
else
|
else
|
||||||
{:ok, actor}
|
{:ok, actor}
|
||||||
end
|
end
|
||||||
|
|
||||||
nil ->
|
nil ->
|
||||||
make_actor_from_nickname(nickname, true)
|
make_actor_from_nickname(nickname, preload: true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ defmodule Mobilizon.Federation.ActivityPub.Actor do
|
||||||
def make_actor_from_nickname(nickname, preload \\ false) do
|
def make_actor_from_nickname(nickname, preload \\ false) do
|
||||||
case WebFinger.finger(nickname) do
|
case WebFinger.finger(nickname) do
|
||||||
{:ok, url} when is_binary(url) ->
|
{:ok, url} when is_binary(url) ->
|
||||||
make_actor_from_url(url, preload)
|
make_actor_from_url(url, preload: preload)
|
||||||
|
|
||||||
{:error, e} ->
|
{:error, e} ->
|
||||||
{:error, e}
|
{:error, e}
|
||||||
|
|
|
@ -49,8 +49,11 @@ defmodule Mobilizon.Federation.ActivityPub.Fetcher do
|
||||||
{:error, :content_not_json}
|
{:error, :content_not_json}
|
||||||
|
|
||||||
{:ok, %Tesla.Env{} = res} ->
|
{:ok, %Tesla.Env{} = res} ->
|
||||||
Logger.debug("Resource returned bad HTTP code inspect #{res}")
|
Logger.debug("Resource returned bad HTTP code #{inspect(res)}")
|
||||||
{:error, :http_error}
|
{:error, :http_error}
|
||||||
|
|
||||||
|
{:error, err} ->
|
||||||
|
{:error, err}
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
{:error, :invalid_url}
|
{:error, :invalid_url}
|
||||||
|
@ -122,39 +125,25 @@ defmodule Mobilizon.Federation.ActivityPub.Fetcher do
|
||||||
"""
|
"""
|
||||||
@spec fetch_and_prepare_actor_from_url(String.t()) ::
|
@spec fetch_and_prepare_actor_from_url(String.t()) ::
|
||||||
{:ok, map()} | {:error, fetch_actor_errors}
|
{:ok, map()} | {:error, fetch_actor_errors}
|
||||||
def fetch_and_prepare_actor_from_url(url) do
|
def fetch_and_prepare_actor_from_url(url, options \\ []) do
|
||||||
Logger.debug("Fetching and preparing actor from url")
|
Logger.debug("Fetching and preparing actor from url")
|
||||||
Logger.debug(inspect(url))
|
Logger.debug(inspect(url))
|
||||||
|
|
||||||
case Tesla.get(url,
|
case fetch(url, options) do
|
||||||
headers: [{"Accept", "application/activity+json"}],
|
{:ok, data} ->
|
||||||
follow_redirect: true
|
case ActorConverter.as_to_model_data(data) do
|
||||||
) do
|
{:error, :actor_not_allowed_type} ->
|
||||||
{:ok, %{status: 200, body: body}} ->
|
{:error, :actor_not_allowed_type}
|
||||||
Logger.debug("response okay, now decoding json")
|
|
||||||
|
|
||||||
case Jason.decode(body) do
|
map when is_map(map) ->
|
||||||
{:ok, data} when is_map(data) ->
|
{:ok, map}
|
||||||
Logger.debug("Got activity+json response at actor's endpoint, now converting data")
|
|
||||||
|
|
||||||
case ActorConverter.as_to_model_data(data) do
|
|
||||||
{:error, :actor_not_allowed_type} ->
|
|
||||||
{:error, :actor_not_allowed_type}
|
|
||||||
|
|
||||||
map when is_map(map) ->
|
|
||||||
{:ok, map}
|
|
||||||
end
|
|
||||||
|
|
||||||
{:error, %Jason.DecodeError{} = e} ->
|
|
||||||
Logger.warn("Could not decode actor at fetch #{url}, #{inspect(e)}")
|
|
||||||
{:error, :json_decode_error}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
{:ok, %{status: 410}} ->
|
{:error, :http_gone} ->
|
||||||
Logger.info("Response HTTP 410")
|
Logger.info("Response HTTP 410")
|
||||||
{:error, :actor_deleted}
|
{:error, :actor_deleted}
|
||||||
|
|
||||||
{:ok, %Tesla.Env{}} ->
|
{:error, :http_error} ->
|
||||||
Logger.info("Non 200 HTTP Code")
|
Logger.info("Non 200 HTTP Code")
|
||||||
{:error, :http_error}
|
{:error, :http_error}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ defmodule Mobilizon.Federation.ActivityPub.Refresher do
|
||||||
|
|
||||||
@spec fetch_group(String.t(), Actor.t()) :: :ok | {:error, fetch_actor_errors}
|
@spec fetch_group(String.t(), Actor.t()) :: :ok | {:error, fetch_actor_errors}
|
||||||
def fetch_group(group_url, %Actor{} = on_behalf_of) do
|
def fetch_group(group_url, %Actor{} = on_behalf_of) do
|
||||||
case ActivityPubActor.make_actor_from_url(group_url) do
|
case ActivityPubActor.make_actor_from_url(group_url, on_behalf_of: on_behalf_of) do
|
||||||
{:error, err}
|
{:error, err}
|
||||||
when err in [:actor_deleted, :http_error, :json_decode_error, :actor_is_local] ->
|
when err in [:actor_deleted, :http_error, :json_decode_error, :actor_is_local] ->
|
||||||
Logger.debug("Error while making actor")
|
Logger.debug("Error while making actor")
|
||||||
|
|
|
@ -114,8 +114,12 @@ defmodule Mobilizon.Federation.HTTPSignatures.Signature do
|
||||||
Logger.debug("headers")
|
Logger.debug("headers")
|
||||||
Logger.debug(inspect(headers))
|
Logger.debug(inspect(headers))
|
||||||
|
|
||||||
with {:ok, key} <- prepare_public_key(keys) do
|
case prepare_public_key(keys) do
|
||||||
HTTPSignatures.sign(key, actor.url <> "#main-key", headers)
|
{:ok, key} ->
|
||||||
|
HTTPSignatures.sign(key, actor.url <> "#main-key", headers)
|
||||||
|
|
||||||
|
{:error, :pem_decode_error} ->
|
||||||
|
raise ArgumentError, message: "Failed to prepare public keys for #{actor.url}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -129,7 +133,7 @@ defmodule Mobilizon.Federation.HTTPSignatures.Signature do
|
||||||
|
|
||||||
@spec generate_date_header(NaiveDateTime.t()) :: String.t()
|
@spec generate_date_header(NaiveDateTime.t()) :: String.t()
|
||||||
def generate_date_header(%NaiveDateTime{} = date) do
|
def generate_date_header(%NaiveDateTime{} = date) do
|
||||||
Timex.format!(date, "{WDshort}, {0D} {Mshort} {YYYY} {h24}:{m}:{s} GMT")
|
Timex.lformat!(date, "{WDshort}, {0D} {Mshort} {YYYY} {h24}:{m}:{s} GMT", "en")
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec generate_request_target(String.t(), String.t()) :: String.t()
|
@spec generate_request_target(String.t(), String.t()) :: String.t()
|
||||||
|
|
|
@ -48,6 +48,7 @@ defmodule Mobilizon.Web.Plugs.HTTPSignatures do
|
||||||
signature_valid = HTTPSignatures.validate_conn(conn)
|
signature_valid = HTTPSignatures.validate_conn(conn)
|
||||||
Logger.debug("Is signature valid ? #{inspect(signature_valid)}")
|
Logger.debug("Is signature valid ? #{inspect(signature_valid)}")
|
||||||
date_valid = date_valid?(conn)
|
date_valid = date_valid?(conn)
|
||||||
|
Logger.debug("Is date valid ? #{inspect(date_valid)}")
|
||||||
assign(conn, :valid_signature, signature_valid && date_valid)
|
assign(conn, :valid_signature, signature_valid && date_valid)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -48,9 +48,10 @@ defmodule Mobilizon.Web.Plugs.MappedSignatureToIdentity do
|
||||||
|
|
||||||
# if this has payload make sure it is signed by the same actor that made it
|
# if this has payload make sure it is signed by the same actor that made it
|
||||||
def call(%{assigns: %{valid_signature: true}, params: %{"actor" => actor}} = conn, _opts) do
|
def call(%{assigns: %{valid_signature: true}, params: %{"actor" => actor}} = conn, _opts) do
|
||||||
with actor_id <- Utils.get_url(actor),
|
with actor_id when actor_id != nil <- Utils.get_url(actor),
|
||||||
{:actor, %Actor{} = actor} <- {:actor, actor_from_key_id(conn)},
|
{:actor, %Actor{} = actor} <- {:actor, actor_from_key_id(conn)},
|
||||||
{:actor_match, true} <- {:actor_match, actor.url == actor_id} do
|
{:actor_match, true} <- {:actor_match, actor.url == actor_id} do
|
||||||
|
Logger.debug("Mapped identity to #{actor.url} from actor param")
|
||||||
assign(conn, :actor, actor)
|
assign(conn, :actor, actor)
|
||||||
else
|
else
|
||||||
{:actor_match, false} ->
|
{:actor_match, false} ->
|
||||||
|
@ -58,7 +59,7 @@ defmodule Mobilizon.Web.Plugs.MappedSignatureToIdentity do
|
||||||
Logger.debug("key_id=#{key_id_from_conn(conn)}, actor=#{actor}")
|
Logger.debug("key_id=#{key_id_from_conn(conn)}, actor=#{actor}")
|
||||||
assign(conn, :valid_signature, false)
|
assign(conn, :valid_signature, false)
|
||||||
|
|
||||||
# remove me once testsuite uses mapped capabilities instead of what we do now
|
# TODO: remove me once testsuite uses mapped capabilities instead of what we do now
|
||||||
{:actor, nil} ->
|
{:actor, nil} ->
|
||||||
Logger.debug("Failed to map identity from signature (lookup failure)")
|
Logger.debug("Failed to map identity from signature (lookup failure)")
|
||||||
Logger.debug("key_id=#{key_id_from_conn(conn)}, actor=#{actor}")
|
Logger.debug("key_id=#{key_id_from_conn(conn)}, actor=#{actor}")
|
||||||
|
@ -70,6 +71,7 @@ defmodule Mobilizon.Web.Plugs.MappedSignatureToIdentity do
|
||||||
def call(%{assigns: %{valid_signature: true}} = conn, _opts) do
|
def call(%{assigns: %{valid_signature: true}} = conn, _opts) do
|
||||||
case actor_from_key_id(conn) do
|
case actor_from_key_id(conn) do
|
||||||
%Actor{} = actor ->
|
%Actor{} = actor ->
|
||||||
|
Logger.debug("Mapped identity to #{actor.url} from signed fetch")
|
||||||
assign(conn, :actor, actor)
|
assign(conn, :actor, actor)
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
|
|
|
@ -12,6 +12,7 @@ defmodule Mobilizon.Web.ActivityPub.ActorView do
|
||||||
alias Mobilizon.Resources.Resource
|
alias Mobilizon.Resources.Resource
|
||||||
alias Mobilizon.Storage.Page
|
alias Mobilizon.Storage.Page
|
||||||
alias Mobilizon.Todos.TodoList
|
alias Mobilizon.Todos.TodoList
|
||||||
|
require Logger
|
||||||
|
|
||||||
@private_visibility_empty_collection %{elements: [], total: 0}
|
@private_visibility_empty_collection %{elements: [], total: 0}
|
||||||
@json_ld_header Utils.make_json_ld_header()
|
@json_ld_header Utils.make_json_ld_header()
|
||||||
|
@ -39,9 +40,16 @@ defmodule Mobilizon.Web.ActivityPub.ActorView do
|
||||||
page = Map.get(args, :page, 1)
|
page = Map.get(args, :page, 1)
|
||||||
collection_name = String.trim_trailing(view_name, ".json")
|
collection_name = String.trim_trailing(view_name, ".json")
|
||||||
collection_name = String.to_existing_atom(collection_name)
|
collection_name = String.to_existing_atom(collection_name)
|
||||||
|
actor_applicant = Map.get(args, :actor_applicant)
|
||||||
|
|
||||||
|
Logger.debug("Rendering actor collection #{inspect(collection_name)}")
|
||||||
|
|
||||||
|
Logger.debug(
|
||||||
|
"Using authenticated fetch with actor #{if actor_applicant, do: actor_applicant.url, else: nil}"
|
||||||
|
)
|
||||||
|
|
||||||
%{total: total, elements: elements} =
|
%{total: total, elements: elements} =
|
||||||
if can_get_collection?(collection_name, actor, Map.get(args, :actor_applicant)),
|
if can_get_collection?(collection_name, actor, actor_applicant),
|
||||||
do: fetch_collection(collection_name, actor, page),
|
do: fetch_collection(collection_name, actor, page),
|
||||||
else: default_collection(collection_name, actor, page)
|
else: default_collection(collection_name, actor, page)
|
||||||
|
|
||||||
|
@ -127,8 +135,13 @@ defmodule Mobilizon.Web.ActivityPub.ActorView do
|
||||||
when visibility in [:public, :unlisted] and collection in [:outbox, :followers, :following],
|
when visibility in [:public, :unlisted] and collection in [:outbox, :followers, :following],
|
||||||
do: true
|
do: true
|
||||||
|
|
||||||
defp can_get_collection?(_collection_name, %Actor{} = actor, %Actor{} = actor_applicant),
|
defp can_get_collection?(_collection_name, %Actor{} = actor, %Actor{} = actor_applicant) do
|
||||||
do: actor_applicant_group_member?(actor, actor_applicant)
|
Logger.debug(
|
||||||
|
"Testing if #{actor_applicant.url} can be allowed access to #{actor.url} private collections"
|
||||||
|
)
|
||||||
|
|
||||||
|
actor_applicant_group_member?(actor, actor_applicant)
|
||||||
|
end
|
||||||
|
|
||||||
defp can_get_collection?(_, _, _), do: false
|
defp can_get_collection?(_, _, _), do: false
|
||||||
|
|
||||||
|
|
|
@ -47,10 +47,17 @@ defmodule Mobilizon.Federation.ActivityPubTest do
|
||||||
File.read!("test/fixtures/mastodon-status-2.json")
|
File.read!("test/fixtures/mastodon-status-2.json")
|
||||||
|> Jason.decode!()
|
|> Jason.decode!()
|
||||||
|
|
||||||
|
actor_data =
|
||||||
|
File.read!("test/fixtures/mastodon-actor.json")
|
||||||
|
|> Jason.decode!()
|
||||||
|
|
||||||
Mock
|
Mock
|
||||||
|> expect(:call, fn
|
|> expect(:call, 2, fn
|
||||||
%{method: :get, url: ^url}, _opts ->
|
%{method: :get, url: ^url}, _opts ->
|
||||||
{:ok, %Tesla.Env{status: 200, body: data}}
|
{:ok, %Tesla.Env{status: 200, body: data}}
|
||||||
|
|
||||||
|
%{method: :get, url: "https://framapiaf.org/users/Framasoft"}, _opts ->
|
||||||
|
{:ok, %Tesla.Env{status: 200, body: actor_data}}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
{:ok, object} = ActivityPub.fetch_object_from_url(url)
|
{:ok, object} = ActivityPub.fetch_object_from_url(url)
|
||||||
|
@ -72,13 +79,20 @@ defmodule Mobilizon.Federation.ActivityPubTest do
|
||||||
File.read!("test/fixtures/mastodon-status-4.json")
|
File.read!("test/fixtures/mastodon-status-4.json")
|
||||||
|> Jason.decode!()
|
|> Jason.decode!()
|
||||||
|
|
||||||
|
actor_data =
|
||||||
|
File.read!("test/fixtures/mastodon-actor.json")
|
||||||
|
|> Jason.decode!()
|
||||||
|
|
||||||
Mock
|
Mock
|
||||||
|> expect(:call, 2, fn
|
|> expect(:call, 3, fn
|
||||||
%{method: :get, url: ^url}, _opts ->
|
%{method: :get, url: ^url}, _opts ->
|
||||||
{:ok, %Tesla.Env{status: 200, body: data}}
|
{:ok, %Tesla.Env{status: 200, body: data}}
|
||||||
|
|
||||||
%{method: :get, url: ^reply_to_url}, _opts ->
|
%{method: :get, url: ^reply_to_url}, _opts ->
|
||||||
{:ok, %Tesla.Env{status: 200, body: reply_to_data}}
|
{:ok, %Tesla.Env{status: 200, body: reply_to_data}}
|
||||||
|
|
||||||
|
%{method: :get, url: "https://pirateradio.social/users/captain"}, _opts ->
|
||||||
|
{:ok, %Tesla.Env{status: 200, body: actor_data}}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
{:ok, object} = ActivityPub.fetch_object_from_url(url)
|
{:ok, object} = ActivityPub.fetch_object_from_url(url)
|
||||||
|
@ -98,13 +112,26 @@ defmodule Mobilizon.Federation.ActivityPubTest do
|
||||||
File.read!("test/fixtures/peertube-video.json")
|
File.read!("test/fixtures/peertube-video.json")
|
||||||
|> Jason.decode!()
|
|> Jason.decode!()
|
||||||
|
|
||||||
|
actor_data =
|
||||||
|
File.read!("test/fixtures/mastodon-actor.json")
|
||||||
|
|> Jason.decode!()
|
||||||
|
|
||||||
Mock
|
Mock
|
||||||
|> expect(:call, 2, fn
|
|> expect(:call, 5, fn
|
||||||
%{method: :get, url: ^url}, _opts ->
|
%{method: :get, url: ^url}, _opts ->
|
||||||
{:ok, %Tesla.Env{status: 200, body: data}}
|
{:ok, %Tesla.Env{status: 200, body: data}}
|
||||||
|
|
||||||
%{method: :get, url: ^origin_url}, _opts ->
|
%{method: :get, url: ^origin_url}, _opts ->
|
||||||
{:ok, %Tesla.Env{status: 200, body: origin_data}}
|
{:ok, %Tesla.Env{status: 200, body: origin_data}}
|
||||||
|
|
||||||
|
%{method: :get, url: "https://diaspodon.fr/users/dada"}, _opts ->
|
||||||
|
{:ok, %Tesla.Env{status: 200, body: actor_data}}
|
||||||
|
|
||||||
|
%{method: :get, url: "https://framatube.org/accounts/framasoft"}, _opts ->
|
||||||
|
{:ok, %Tesla.Env{status: 200, body: actor_data}}
|
||||||
|
|
||||||
|
%{method: :get, url: "https://framapiaf.org/users/Pouhiou"}, _opts ->
|
||||||
|
{:ok, %Tesla.Env{status: 200, body: actor_data}}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
{:ok, object} = ActivityPub.fetch_object_from_url(url)
|
{:ok, object} = ActivityPub.fetch_object_from_url(url)
|
||||||
|
|
|
@ -1,39 +1,72 @@
|
||||||
defmodule Mobilizon.Federation.ActivityPub.ActorTest do
|
defmodule Mobilizon.Federation.ActivityPub.ActorTest do
|
||||||
use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney
|
|
||||||
use Mobilizon.DataCase
|
use Mobilizon.DataCase
|
||||||
|
import Mox
|
||||||
import Mock
|
import Mock
|
||||||
|
|
||||||
alias Mobilizon.Actors
|
alias Mobilizon.Actors
|
||||||
alias Mobilizon.Actors.Actor
|
alias Mobilizon.Actors.Actor
|
||||||
|
|
||||||
alias Mobilizon.Federation.ActivityPub.Actor, as: ActivityPubActor
|
alias Mobilizon.Federation.ActivityPub.Actor, as: ActivityPubActor
|
||||||
alias Mobilizon.Federation.ActivityPub.{Fetcher, Relay}
|
alias Mobilizon.Federation.ActivityPub.Relay
|
||||||
|
alias Mobilizon.Service.HTTP.ActivityPub.Mock
|
||||||
|
|
||||||
describe "fetching actor from its url" do
|
describe "fetching actor from its url" do
|
||||||
|
@actor_url "https://framapiaf.org/users/tcit"
|
||||||
test "returns an actor from nickname" do
|
test "returns an actor from nickname" do
|
||||||
use_cassette "activity_pub/fetch_tcit@framapiaf.org" do
|
actor_data =
|
||||||
assert {:ok,
|
File.read!("test/fixtures/mastodon-actor.json")
|
||||||
%Actor{preferred_username: "tcit", domain: "framapiaf.org", visibility: :public} =
|
|> Jason.decode!()
|
||||||
_actor} = ActivityPubActor.make_actor_from_nickname("tcit@framapiaf.org")
|
|> Map.put("id", @actor_url)
|
||||||
end
|
|> Map.put("preferredUsername", "tcit")
|
||||||
|
|> Map.put("discoverable", true)
|
||||||
|
|
||||||
use_cassette "activity_pub/fetch_tcit@framapiaf.org_not_discoverable" do
|
Mock
|
||||||
assert {:ok,
|
|> expect(:call, fn
|
||||||
%Actor{preferred_username: "tcit", domain: "framapiaf.org", visibility: :unlisted} =
|
%{method: :get, url: @actor_url}, _opts ->
|
||||||
_actor} = ActivityPubActor.make_actor_from_nickname("tcit@framapiaf.org")
|
{:ok, %Tesla.Env{status: 200, body: actor_data}}
|
||||||
end
|
end)
|
||||||
|
|
||||||
|
assert {:ok,
|
||||||
|
%Actor{preferred_username: "tcit", domain: "framapiaf.org", visibility: :public} =
|
||||||
|
_actor} = ActivityPubActor.make_actor_from_nickname("tcit@framapiaf.org")
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns an actor from nickname when not discoverable" do
|
||||||
|
actor_data =
|
||||||
|
File.read!("test/fixtures/mastodon-actor.json")
|
||||||
|
|> Jason.decode!()
|
||||||
|
|> Map.put("id", @actor_url)
|
||||||
|
|> Map.put("preferredUsername", "tcit")
|
||||||
|
|
||||||
|
Mock
|
||||||
|
|> expect(:call, fn
|
||||||
|
%{method: :get, url: @actor_url}, _opts ->
|
||||||
|
{:ok, %Tesla.Env{status: 200, body: actor_data}}
|
||||||
|
end)
|
||||||
|
|
||||||
|
assert {:ok,
|
||||||
|
%Actor{preferred_username: "tcit", domain: "framapiaf.org", visibility: :unlisted} =
|
||||||
|
_actor} = ActivityPubActor.make_actor_from_nickname("tcit@framapiaf.org")
|
||||||
end
|
end
|
||||||
|
|
||||||
@actor_url "https://framapiaf.org/users/tcit"
|
|
||||||
test "returns an actor from url" do
|
test "returns an actor from url" do
|
||||||
|
actor_data =
|
||||||
|
File.read!("test/fixtures/mastodon-actor.json")
|
||||||
|
|> Jason.decode!()
|
||||||
|
|> Map.put("id", @actor_url)
|
||||||
|
|> Map.put("preferredUsername", "tcit")
|
||||||
|
|
||||||
|
Mock
|
||||||
|
|> expect(:call, fn
|
||||||
|
%{method: :get, url: @actor_url}, _opts ->
|
||||||
|
{:ok, %Tesla.Env{status: 200, body: actor_data}}
|
||||||
|
end)
|
||||||
|
|
||||||
# Initial fetch
|
# Initial fetch
|
||||||
use_cassette "activity_pub/fetch_framapiaf.org_users_tcit" do
|
# Unlisted because discoverable is not present in the JSON payload
|
||||||
# Unlisted because discoverable is not present in the JSON payload
|
assert {:ok,
|
||||||
assert {:ok,
|
%Actor{preferred_username: "tcit", domain: "framapiaf.org", visibility: :unlisted}} =
|
||||||
%Actor{preferred_username: "tcit", domain: "framapiaf.org", visibility: :unlisted}} =
|
ActivityPubActor.get_or_fetch_actor_by_url(@actor_url)
|
||||||
ActivityPubActor.get_or_fetch_actor_by_url(@actor_url)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Fetch uses cache if Actors.needs_update? returns false
|
# Fetch uses cache if Actors.needs_update? returns false
|
||||||
with_mocks([
|
with_mocks([
|
||||||
|
@ -49,7 +82,7 @@ defmodule Mobilizon.Federation.ActivityPub.ActorTest do
|
||||||
needs_update?: fn _ -> false end
|
needs_update?: fn _ -> false end
|
||||||
]},
|
]},
|
||||||
{ActivityPubActor, [:passthrough],
|
{ActivityPubActor, [:passthrough],
|
||||||
make_actor_from_url: fn @actor_url, false ->
|
make_actor_from_url: fn @actor_url, preload: false ->
|
||||||
{:ok,
|
{:ok,
|
||||||
%Actor{
|
%Actor{
|
||||||
preferred_username: "tcit",
|
preferred_username: "tcit",
|
||||||
|
@ -61,7 +94,7 @@ defmodule Mobilizon.Federation.ActivityPub.ActorTest do
|
||||||
ActivityPubActor.get_or_fetch_actor_by_url(@actor_url)
|
ActivityPubActor.get_or_fetch_actor_by_url(@actor_url)
|
||||||
|
|
||||||
assert_called(Actors.needs_update?(:_))
|
assert_called(Actors.needs_update?(:_))
|
||||||
refute called(ActivityPubActor.make_actor_from_url(@actor_url, false))
|
refute called(ActivityPubActor.make_actor_from_url(@actor_url, preload: false))
|
||||||
end
|
end
|
||||||
|
|
||||||
# Fetch doesn't use cache if Actors.needs_update? returns true
|
# Fetch doesn't use cache if Actors.needs_update? returns true
|
||||||
|
@ -78,7 +111,7 @@ defmodule Mobilizon.Federation.ActivityPub.ActorTest do
|
||||||
needs_update?: fn _ -> true end
|
needs_update?: fn _ -> true end
|
||||||
]},
|
]},
|
||||||
{ActivityPubActor, [:passthrough],
|
{ActivityPubActor, [:passthrough],
|
||||||
make_actor_from_url: fn @actor_url, false ->
|
make_actor_from_url: fn @actor_url, preload: false ->
|
||||||
{:ok,
|
{:ok,
|
||||||
%Actor{
|
%Actor{
|
||||||
preferred_username: "tcit",
|
preferred_username: "tcit",
|
||||||
|
@ -92,24 +125,21 @@ defmodule Mobilizon.Federation.ActivityPub.ActorTest do
|
||||||
assert_called(ActivityPubActor.get_or_fetch_actor_by_url(@actor_url))
|
assert_called(ActivityPubActor.get_or_fetch_actor_by_url(@actor_url))
|
||||||
assert_called(Actors.get_actor_by_url(@actor_url, false))
|
assert_called(Actors.get_actor_by_url(@actor_url, false))
|
||||||
assert_called(Actors.needs_update?(:_))
|
assert_called(Actors.needs_update?(:_))
|
||||||
assert_called(ActivityPubActor.make_actor_from_url(@actor_url, false))
|
assert_called(ActivityPubActor.make_actor_from_url(@actor_url, preload: false))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "handles remote actor being deleted" do
|
test "handles remote actor being deleted" do
|
||||||
with_mocks([
|
Mock
|
||||||
{Fetcher, [:passthrough],
|
|> expect(:call, fn
|
||||||
fetch_and_prepare_actor_from_url: fn @actor_url ->
|
%{method: :get, url: @actor_url}, _opts ->
|
||||||
{:error, :actor_deleted}
|
{:ok, %Tesla.Env{status: 410, body: ""}}
|
||||||
end}
|
end)
|
||||||
]) do
|
|
||||||
assert match?(
|
|
||||||
{:error, :actor_deleted},
|
|
||||||
ActivityPubActor.make_actor_from_url(@actor_url, false)
|
|
||||||
)
|
|
||||||
|
|
||||||
assert_called(Fetcher.fetch_and_prepare_actor_from_url(@actor_url))
|
assert match?(
|
||||||
end
|
{:error, :actor_deleted},
|
||||||
|
ActivityPubActor.make_actor_from_url(@actor_url, preload: false)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@public_url "https://www.w3.org/ns/activitystreams#Public"
|
@public_url "https://www.w3.org/ns/activitystreams#Public"
|
||||||
|
|
|
@ -36,12 +36,79 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier.CommentsTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it fetches replied-to activities if we don't have them" do
|
test "it fetches replied-to activities if we don't have them" do
|
||||||
data =
|
actor_data = File.read!("test/fixtures/mastodon-actor.json") |> Jason.decode!()
|
||||||
File.read!("test/fixtures/mastodon-post-activity.json")
|
status_data = File.read!("test/fixtures/mastodon-status-2.json") |> Jason.decode!()
|
||||||
|
|
||||||
|
reply_to_data =
|
||||||
|
File.read!("test/fixtures/pleroma-comment-object.json")
|
||||||
|> Jason.decode!()
|
|> Jason.decode!()
|
||||||
|
|
||||||
reply_to_url = "https://fedi.absturztau.be/objects/1726cdc7-4f2a-4ddb-9c68-03d27c98c3d9"
|
reply_to_url = "https://fedi.absturztau.be/objects/1726cdc7-4f2a-4ddb-9c68-03d27c98c3d9"
|
||||||
|
|
||||||
|
Mock
|
||||||
|
|> expect(:call, 5, fn
|
||||||
|
%{method: :get, url: "https://framapiaf.org/users/admin"}, _opts ->
|
||||||
|
{:ok,
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body:
|
||||||
|
actor_data
|
||||||
|
|> Map.put("id", "https://framapiaf.org/users/admin")
|
||||||
|
|> Map.put("preferredUsername", "admin")
|
||||||
|
}}
|
||||||
|
|
||||||
|
%{method: :get, url: "https://framapiaf.org/users/tcit"}, _opts ->
|
||||||
|
{:ok,
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body:
|
||||||
|
actor_data
|
||||||
|
|> Map.put("id", "https://framapiaf.org/users/tcit")
|
||||||
|
|> Map.put("preferredUsername", "tcit")
|
||||||
|
}}
|
||||||
|
|
||||||
|
%{method: :get, url: "https://framapiaf.org/users/Framasoft"}, _opts ->
|
||||||
|
{:ok,
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body:
|
||||||
|
actor_data
|
||||||
|
|> Map.put("id", "https://framapiaf.org/users/Framasoft")
|
||||||
|
|> Map.put("preferredUsername", "Framasoft")
|
||||||
|
}}
|
||||||
|
|
||||||
|
%{
|
||||||
|
method: :get,
|
||||||
|
url: "https://fedi.absturztau.be/objects/1726cdc7-4f2a-4ddb-9c68-03d27c98c3d9"
|
||||||
|
},
|
||||||
|
_opts ->
|
||||||
|
{:ok,
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body:
|
||||||
|
status_data
|
||||||
|
|> Map.put(
|
||||||
|
"id",
|
||||||
|
"https://fedi.absturztau.be/objects/1726cdc7-4f2a-4ddb-9c68-03d27c98c3d9"
|
||||||
|
)
|
||||||
|
|> Map.put("actor", "https://fedi.absturztau.be/users/dqn")
|
||||||
|
}}
|
||||||
|
|
||||||
|
%{method: :get, url: "https://fedi.absturztau.be/users/dqn"}, _opts ->
|
||||||
|
{:ok,
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body: Map.put(actor_data, "id", "https://fedi.absturztau.be/users/dqn")
|
||||||
|
}}
|
||||||
|
|
||||||
|
%{method: :get, url: ^reply_to_url}, _opts ->
|
||||||
|
{:ok, %Tesla.Env{status: 200, body: reply_to_data}}
|
||||||
|
end)
|
||||||
|
|
||||||
|
data =
|
||||||
|
File.read!("test/fixtures/mastodon-post-activity.json")
|
||||||
|
|> Jason.decode!()
|
||||||
|
|
||||||
object =
|
object =
|
||||||
data["object"]
|
data["object"]
|
||||||
|> Map.put("inReplyTo", reply_to_url)
|
|> Map.put("inReplyTo", reply_to_url)
|
||||||
|
@ -50,16 +117,6 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier.CommentsTest do
|
||||||
data
|
data
|
||||||
|> Map.put("object", object)
|
|> Map.put("object", object)
|
||||||
|
|
||||||
reply_to_data =
|
|
||||||
File.read!("test/fixtures/pleroma-comment-object.json")
|
|
||||||
|> Jason.decode!()
|
|
||||||
|
|
||||||
Mock
|
|
||||||
|> expect(:call, fn
|
|
||||||
%{method: :get, url: ^reply_to_url}, _opts ->
|
|
||||||
{:ok, %Tesla.Env{status: 200, body: reply_to_data}}
|
|
||||||
end)
|
|
||||||
|
|
||||||
{:ok, returned_activity, _} = Transmogrifier.handle_incoming(data)
|
{:ok, returned_activity, _} = Transmogrifier.handle_incoming(data)
|
||||||
|
|
||||||
%Comment{} =
|
%Comment{} =
|
||||||
|
@ -75,6 +132,25 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier.CommentsTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it doesn't saves replies to an event if the event doesn't accept comments" do
|
test "it doesn't saves replies to an event if the event doesn't accept comments" do
|
||||||
|
actor_data = File.read!("test/fixtures/mastodon-actor.json") |> Jason.decode!()
|
||||||
|
|
||||||
|
Mock
|
||||||
|
|> expect(:call, 2, fn
|
||||||
|
%{method: :get, url: "https://framapiaf.org/users/admin"}, _opts ->
|
||||||
|
{:ok,
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body: Map.put(actor_data, "id", "https://framapiaf.org/users/admin")
|
||||||
|
}}
|
||||||
|
|
||||||
|
%{method: :get, url: "https://framapiaf.org/users/tcit"}, _opts ->
|
||||||
|
{:ok,
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body: Map.put(actor_data, "id", "https://framapiaf.org/users/tcit")
|
||||||
|
}}
|
||||||
|
end)
|
||||||
|
|
||||||
data =
|
data =
|
||||||
File.read!("test/fixtures/mastodon-post-activity.json")
|
File.read!("test/fixtures/mastodon-post-activity.json")
|
||||||
|> Jason.decode!()
|
|> Jason.decode!()
|
||||||
|
@ -94,6 +170,31 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier.CommentsTest do
|
||||||
|
|
||||||
@url_404 "https://404.site/whatever"
|
@url_404 "https://404.site/whatever"
|
||||||
test "it does not crash if the object in inReplyTo can't be fetched" do
|
test "it does not crash if the object in inReplyTo can't be fetched" do
|
||||||
|
actor_data = File.read!("test/fixtures/mastodon-actor.json") |> Jason.decode!()
|
||||||
|
|
||||||
|
Mock
|
||||||
|
|> expect(:call, 2, fn
|
||||||
|
%{method: :get, url: "https://framapiaf.org/users/admin"}, _opts ->
|
||||||
|
{:ok,
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body:
|
||||||
|
actor_data
|
||||||
|
|> Map.put("id", "https://framapiaf.org/users/admin")
|
||||||
|
|> Map.put("preferredUsername", "admin")
|
||||||
|
}}
|
||||||
|
|
||||||
|
%{method: :get, url: "https://framapiaf.org/users/tcit"}, _opts ->
|
||||||
|
{:ok,
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body:
|
||||||
|
actor_data
|
||||||
|
|> Map.put("id", "https://framapiaf.org/users/tcit")
|
||||||
|
|> Map.put("preferredUsername", "tcit")
|
||||||
|
}}
|
||||||
|
end)
|
||||||
|
|
||||||
data =
|
data =
|
||||||
File.read!("test/fixtures/mastodon-post-activity.json")
|
File.read!("test/fixtures/mastodon-post-activity.json")
|
||||||
|> Jason.decode!()
|
|> Jason.decode!()
|
||||||
|
@ -118,6 +219,31 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier.CommentsTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it ignores incoming private notes" do
|
test "it ignores incoming private notes" do
|
||||||
|
actor_data = File.read!("test/fixtures/mastodon-actor.json") |> Jason.decode!()
|
||||||
|
|
||||||
|
Mock
|
||||||
|
|> expect(:call, 2, fn
|
||||||
|
%{method: :get, url: "https://framapiaf.org/users/admin"}, _opts ->
|
||||||
|
{:ok,
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body:
|
||||||
|
actor_data
|
||||||
|
|> Map.put("id", "https://framapiaf.org/users/admin")
|
||||||
|
|> Map.put("preferredUsername", "admin")
|
||||||
|
}}
|
||||||
|
|
||||||
|
%{method: :get, url: "https://framapiaf.org/users/tcit"}, _opts ->
|
||||||
|
{:ok,
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body:
|
||||||
|
actor_data
|
||||||
|
|> Map.put("id", "https://framapiaf.org/users/tcit")
|
||||||
|
|> Map.put("preferredUsername", "tcit")
|
||||||
|
}}
|
||||||
|
end)
|
||||||
|
|
||||||
data = File.read!("test/fixtures/mastodon-post-activity-private.json") |> Jason.decode!()
|
data = File.read!("test/fixtures/mastodon-post-activity-private.json") |> Jason.decode!()
|
||||||
event = insert(:event)
|
event = insert(:event)
|
||||||
object = data["object"]
|
object = data["object"]
|
||||||
|
@ -128,16 +254,33 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier.CommentsTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it works for incoming notices" do
|
test "it works for incoming notices" do
|
||||||
|
actor_data = File.read!("test/fixtures/mastodon-actor.json") |> Jason.decode!()
|
||||||
data = File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!()
|
data = File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!()
|
||||||
|
|
||||||
|
Mock
|
||||||
|
|> expect(:call, 2, fn
|
||||||
|
%{method: :get, url: "https://framapiaf.org/users/admin"}, _opts ->
|
||||||
|
{:ok,
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body: Map.put(actor_data, "id", "https://framapiaf.org/users/admin")
|
||||||
|
}}
|
||||||
|
|
||||||
|
%{method: :get, url: "https://framapiaf.org/users/tcit"}, _opts ->
|
||||||
|
{:ok,
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body: Map.put(actor_data, "id", "https://framapiaf.org/users/tcit")
|
||||||
|
}}
|
||||||
|
end)
|
||||||
|
|
||||||
{:ok, %Activity{data: data, local: false}, _} = Transmogrifier.handle_incoming(data)
|
{:ok, %Activity{data: data, local: false}, _} = Transmogrifier.handle_incoming(data)
|
||||||
|
|
||||||
assert data["id"] ==
|
assert data["id"] ==
|
||||||
"https://framapiaf.org/users/admin/statuses/99512778738411822/activity"
|
"https://framapiaf.org/users/admin/statuses/99512778738411822/activity"
|
||||||
|
|
||||||
assert data["to"] == [
|
assert data["to"] == [
|
||||||
"https://www.w3.org/ns/activitystreams#Public",
|
"https://www.w3.org/ns/activitystreams#Public"
|
||||||
"https://framapiaf.org/users/tcit"
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# assert data["cc"] == [
|
# assert data["cc"] == [
|
||||||
|
@ -164,6 +307,31 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier.CommentsTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it works for incoming notices with hashtags" do
|
test "it works for incoming notices with hashtags" do
|
||||||
|
actor_data = File.read!("test/fixtures/mastodon-actor.json") |> Jason.decode!()
|
||||||
|
|
||||||
|
Mock
|
||||||
|
|> expect(:call, 2, fn
|
||||||
|
%{method: :get, url: "https://framapiaf.org/users/admin"}, _opts ->
|
||||||
|
{:ok,
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body:
|
||||||
|
actor_data
|
||||||
|
|> Map.put("id", "https://framapiaf.org/users/admin")
|
||||||
|
|> Map.put("preferredUsername", "admin")
|
||||||
|
}}
|
||||||
|
|
||||||
|
%{method: :get, url: "https://framapiaf.org/users/tcit"}, _opts ->
|
||||||
|
{:ok,
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body:
|
||||||
|
actor_data
|
||||||
|
|> Map.put("id", "https://framapiaf.org/users/tcit")
|
||||||
|
|> Map.put("preferredUsername", "tcit")
|
||||||
|
}}
|
||||||
|
end)
|
||||||
|
|
||||||
data = File.read!("test/fixtures/mastodon-post-activity-hashtag.json") |> Jason.decode!()
|
data = File.read!("test/fixtures/mastodon-post-activity-hashtag.json") |> Jason.decode!()
|
||||||
|
|
||||||
{:ok, %Activity{data: data, local: false}, _} = Transmogrifier.handle_incoming(data)
|
{:ok, %Activity{data: data, local: false}, _} = Transmogrifier.handle_incoming(data)
|
||||||
|
|
|
@ -56,6 +56,19 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier.DeleteTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it fails for incoming deletes with spoofed origin" do
|
test "it fails for incoming deletes with spoofed origin" do
|
||||||
|
actor_data =
|
||||||
|
File.read!("test/fixtures/mastodon-actor.json")
|
||||||
|
|> Jason.decode!()
|
||||||
|
|
||||||
|
Mock
|
||||||
|
|> expect(:call, 2, fn
|
||||||
|
%{method: :get, url: "https://framapiaf.org/users/peertube"}, _opts ->
|
||||||
|
{:ok, %Tesla.Env{status: 200, body: actor_data}}
|
||||||
|
|
||||||
|
%{method: :get, url: "http://mastodon.example.org/users/gargron"}, _opts ->
|
||||||
|
{:ok, %Tesla.Env{status: 200, body: actor_data}}
|
||||||
|
end)
|
||||||
|
|
||||||
comment = insert(:comment)
|
comment = insert(:comment)
|
||||||
|
|
||||||
announce_data =
|
announce_data =
|
||||||
|
@ -77,7 +90,7 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier.DeleteTest do
|
||||||
data
|
data
|
||||||
|> Map.put("object", object)
|
|> Map.put("object", object)
|
||||||
|
|
||||||
{:error, :unknown_actor} = Transmogrifier.handle_incoming(data)
|
:error = Transmogrifier.handle_incoming(data)
|
||||||
|
|
||||||
assert Discussions.get_comment_from_url(comment.url)
|
assert Discussions.get_comment_from_url(comment.url)
|
||||||
end
|
end
|
||||||
|
@ -132,12 +145,12 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier.DeleteTest do
|
||||||
|> Map.put("id", deleted_actor_url)
|
|> Map.put("id", deleted_actor_url)
|
||||||
|
|
||||||
Mock
|
Mock
|
||||||
|> expect(:call, fn
|
|> expect(:call, 2, fn
|
||||||
%{url: ^deleted_actor_url}, _opts ->
|
%{url: ^deleted_actor_url}, _opts ->
|
||||||
{:ok, %Tesla.Env{status: 200, body: deleted_actor_data}}
|
{:ok, %Tesla.Env{status: 200, body: deleted_actor_data}}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
assert :error == Transmogrifier.handle_incoming(data)
|
assert {:error, "Group object URL remote"} == Transmogrifier.handle_incoming(data)
|
||||||
|
|
||||||
assert Actors.get_actor_by_url(url)
|
assert Actors.get_actor_by_url(url)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,16 +1,31 @@
|
||||||
defmodule Mobilizon.Federation.ActivityPub.Transmogrifier.FollowTest do
|
defmodule Mobilizon.Federation.ActivityPub.Transmogrifier.FollowTest do
|
||||||
use Mobilizon.DataCase
|
use Mobilizon.DataCase
|
||||||
|
import Mox
|
||||||
import ExUnit.CaptureLog
|
import ExUnit.CaptureLog
|
||||||
import Mobilizon.Factory
|
import Mobilizon.Factory
|
||||||
alias Mobilizon.Actors
|
alias Mobilizon.Actors
|
||||||
alias Mobilizon.Actors.Follower
|
alias Mobilizon.Actors.Follower
|
||||||
alias Mobilizon.Federation.ActivityPub.{Actions, Activity, Transmogrifier}
|
alias Mobilizon.Federation.ActivityPub.{Actions, Activity, Transmogrifier}
|
||||||
|
alias Mobilizon.Service.HTTP.ActivityPub.Mock
|
||||||
|
|
||||||
describe "handle incoming follow requests" do
|
describe "handle incoming follow requests" do
|
||||||
test "it works only for groups" do
|
test "it works only for groups" do
|
||||||
actor = insert(:actor)
|
actor = insert(:actor)
|
||||||
|
|
||||||
|
actor_data =
|
||||||
|
File.read!("test/fixtures/mastodon-actor.json")
|
||||||
|
|> Jason.decode!()
|
||||||
|
|
||||||
|
Mock
|
||||||
|
|> expect(:call, fn
|
||||||
|
%{method: :get, url: "https://social.tcit.fr/users/tcit"}, _opts ->
|
||||||
|
{:ok,
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body: Map.put(actor_data, "id", "https://social.tcit.fr/users/tcit")
|
||||||
|
}}
|
||||||
|
end)
|
||||||
|
|
||||||
data =
|
data =
|
||||||
File.read!("test/fixtures/mastodon-follow-activity.json")
|
File.read!("test/fixtures/mastodon-follow-activity.json")
|
||||||
|> Jason.decode!()
|
|> Jason.decode!()
|
||||||
|
@ -27,6 +42,20 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier.FollowTest do
|
||||||
test "it works for incoming follow requests" do
|
test "it works for incoming follow requests" do
|
||||||
actor = insert(:group)
|
actor = insert(:group)
|
||||||
|
|
||||||
|
actor_data =
|
||||||
|
File.read!("test/fixtures/mastodon-actor.json")
|
||||||
|
|> Jason.decode!()
|
||||||
|
|
||||||
|
Mock
|
||||||
|
|> expect(:call, fn
|
||||||
|
%{method: :get, url: "https://social.tcit.fr/users/tcit"}, _opts ->
|
||||||
|
{:ok,
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body: Map.put(actor_data, "id", "https://social.tcit.fr/users/tcit")
|
||||||
|
}}
|
||||||
|
end)
|
||||||
|
|
||||||
data =
|
data =
|
||||||
File.read!("test/fixtures/mastodon-follow-activity.json")
|
File.read!("test/fixtures/mastodon-follow-activity.json")
|
||||||
|> Jason.decode!()
|
|> Jason.decode!()
|
||||||
|
|
|
@ -22,9 +22,12 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier.UndoTest do
|
||||||
|> Jason.decode!()
|
|> Jason.decode!()
|
||||||
|
|
||||||
Mock
|
Mock
|
||||||
|> expect(:call, fn
|
|> expect(:call, 2, fn
|
||||||
%{method: :get, url: "https://framapiaf.org/users/Framasoft"}, _opts ->
|
%{method: :get, url: "https://framapiaf.org/users/Framasoft"}, _opts ->
|
||||||
{:ok, %Tesla.Env{status: 200, body: actor_data}}
|
{:ok, %Tesla.Env{status: 200, body: actor_data}}
|
||||||
|
|
||||||
|
%{method: :get, url: "https://framapiaf.org/users/peertube"}, _opts ->
|
||||||
|
{:ok, %Tesla.Env{status: 200, body: actor_data}}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
{:ok, _, %Comment{}} = Transmogrifier.handle_incoming(announce_data)
|
{:ok, _, %Comment{}} = Transmogrifier.handle_incoming(announce_data)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
defmodule Mobilizon.Federation.ActivityPub.Transmogrifier.UpdateTest do
|
defmodule Mobilizon.Federation.ActivityPub.Transmogrifier.UpdateTest do
|
||||||
use Mobilizon.DataCase
|
use Mobilizon.DataCase
|
||||||
use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney
|
|
||||||
use Oban.Testing, repo: Mobilizon.Storage.Repo
|
use Oban.Testing, repo: Mobilizon.Storage.Repo
|
||||||
import Mobilizon.Factory
|
import Mobilizon.Factory
|
||||||
|
import Mox
|
||||||
|
|
||||||
alias Mobilizon.{Actors, Events, Posts}
|
alias Mobilizon.{Actors, Events, Posts}
|
||||||
alias Mobilizon.Actors.{Actor, Member}
|
alias Mobilizon.Actors.{Actor, Member}
|
||||||
|
@ -10,79 +10,100 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier.UpdateTest do
|
||||||
alias Mobilizon.Posts.Post
|
alias Mobilizon.Posts.Post
|
||||||
alias Mobilizon.Federation.ActivityPub.{Activity, Transmogrifier}
|
alias Mobilizon.Federation.ActivityPub.{Activity, Transmogrifier}
|
||||||
alias Mobilizon.Federation.ActivityStream.Convertible
|
alias Mobilizon.Federation.ActivityStream.Convertible
|
||||||
|
alias Mobilizon.Service.HTTP.ActivityPub.Mock
|
||||||
|
|
||||||
describe "handle incoming update activities" do
|
describe "handle incoming update activities" do
|
||||||
test "it works for incoming update activities on actors" do
|
test "it works for incoming update activities on actors" do
|
||||||
use_cassette "activity_pub/update_actor_activity" do
|
data = File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!()
|
||||||
data = File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!()
|
|
||||||
|
|
||||||
{:ok, %Activity{data: data, local: false}, _} = Transmogrifier.handle_incoming(data)
|
actor_data =
|
||||||
update_data = File.read!("test/fixtures/mastodon-update.json") |> Jason.decode!()
|
File.read!("test/fixtures/mastodon-actor.json")
|
||||||
|
|> Jason.decode!()
|
||||||
|
|
||||||
object =
|
Mock
|
||||||
update_data["object"]
|
|> expect(:call, 2, fn
|
||||||
|> Map.put("actor", data["actor"])
|
%{method: :get, url: "https://framapiaf.org/users/admin"}, _opts ->
|
||||||
|> Map.put("id", data["actor"])
|
{:ok, %Tesla.Env{status: 200, body: actor_data}}
|
||||||
|
|
||||||
update_data =
|
%{method: :get, url: "https://framapiaf.org/users/tcit"}, _opts ->
|
||||||
update_data
|
{:ok, %Tesla.Env{status: 200, body: actor_data}}
|
||||||
|> Map.put("actor", data["actor"])
|
end)
|
||||||
|> Map.put("object", object)
|
|
||||||
|
|
||||||
{:ok, %Activity{data: _data, local: false}, _} =
|
{:ok, %Activity{data: data, local: false}, _} = Transmogrifier.handle_incoming(data)
|
||||||
Transmogrifier.handle_incoming(update_data)
|
update_data = File.read!("test/fixtures/mastodon-update.json") |> Jason.decode!()
|
||||||
|
|
||||||
{:ok, %Actor{} = actor} = Actors.get_actor_by_url(update_data["actor"])
|
object =
|
||||||
assert actor.name == "nextsoft"
|
update_data["object"]
|
||||||
|
|> Map.put("actor", data["actor"])
|
||||||
|
|> Map.put("id", data["actor"])
|
||||||
|
|
||||||
assert actor.summary == "<p>Some bio</p>"
|
update_data =
|
||||||
end
|
update_data
|
||||||
|
|> Map.put("actor", data["actor"])
|
||||||
|
|> Map.put("object", object)
|
||||||
|
|
||||||
|
{:ok, %Activity{data: _data, local: false}, _} = Transmogrifier.handle_incoming(update_data)
|
||||||
|
|
||||||
|
{:ok, %Actor{} = actor} = Actors.get_actor_by_url(update_data["actor"])
|
||||||
|
assert actor.name == "nextsoft"
|
||||||
|
|
||||||
|
assert actor.summary == "<p>Some bio</p>"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it works for incoming update activities on events" do
|
test "it works for incoming update activities on events" do
|
||||||
use_cassette "activity_pub/event_update_activities" do
|
data = File.read!("test/fixtures/mobilizon-post-activity.json") |> Jason.decode!()
|
||||||
data = File.read!("test/fixtures/mobilizon-post-activity.json") |> Jason.decode!()
|
|
||||||
|
|
||||||
{:ok, %Activity{data: data, local: false}, %Event{id: event_id}} =
|
actor_data =
|
||||||
Transmogrifier.handle_incoming(data)
|
File.read!("test/fixtures/mastodon-actor.json")
|
||||||
|
|> Jason.decode!()
|
||||||
|
|
||||||
assert_enqueued(
|
Mock
|
||||||
worker: Mobilizon.Service.Workers.BuildSearch,
|
|> expect(:call, 2, fn
|
||||||
args: %{event_id: event_id, op: :insert_search_event}
|
%{method: :get, url: "https://mobilizon.fr/@metacartes"}, _opts ->
|
||||||
)
|
{:ok, %Tesla.Env{status: 200, body: actor_data}}
|
||||||
|
|
||||||
assert %{success: 1, snoozed: 0, failure: 0} == Oban.drain_queue(queue: :search)
|
%{method: :get, url: "https://framapiaf.org/users/tcit"}, _opts ->
|
||||||
|
{:ok, %Tesla.Env{status: 200, body: actor_data}}
|
||||||
|
end)
|
||||||
|
|
||||||
update_data = File.read!("test/fixtures/mastodon-update.json") |> Jason.decode!()
|
{:ok, %Activity{data: data, local: false}, %Event{id: event_id}} =
|
||||||
|
Transmogrifier.handle_incoming(data)
|
||||||
|
|
||||||
object =
|
assert_enqueued(
|
||||||
data["object"]
|
worker: Mobilizon.Service.Workers.BuildSearch,
|
||||||
|> Map.put("actor", data["actor"])
|
args: %{event_id: event_id, op: :insert_search_event}
|
||||||
|> Map.put("name", "My updated event")
|
)
|
||||||
|> Map.put("id", data["object"]["id"])
|
|
||||||
|> Map.put("type", "Event")
|
|
||||||
|
|
||||||
update_data =
|
assert %{success: 1, snoozed: 0, failure: 0} == Oban.drain_queue(queue: :search)
|
||||||
update_data
|
|
||||||
|> Map.put("actor", data["actor"])
|
|
||||||
|> Map.put("object", object)
|
|
||||||
|
|
||||||
{:ok, %Activity{data: data, local: false}, _} =
|
update_data = File.read!("test/fixtures/mastodon-update.json") |> Jason.decode!()
|
||||||
Transmogrifier.handle_incoming(update_data)
|
|
||||||
|
|
||||||
%Event{} = event = Events.get_event_by_url(data["object"]["id"])
|
object =
|
||||||
|
data["object"]
|
||||||
|
|> Map.put("actor", data["actor"])
|
||||||
|
|> Map.put("name", "My updated event")
|
||||||
|
|> Map.put("id", data["object"]["id"])
|
||||||
|
|> Map.put("type", "Event")
|
||||||
|
|
||||||
assert_enqueued(
|
update_data =
|
||||||
worker: Mobilizon.Service.Workers.BuildSearch,
|
update_data
|
||||||
args: %{event_id: event_id, op: :update_search_event}
|
|> Map.put("actor", data["actor"])
|
||||||
)
|
|> Map.put("object", object)
|
||||||
|
|
||||||
assert %{success: 1, snoozed: 0, failure: 0} == Oban.drain_queue(queue: :search)
|
{:ok, %Activity{data: data, local: false}, _} = Transmogrifier.handle_incoming(update_data)
|
||||||
|
|
||||||
assert event.title == "My updated event"
|
%Event{} = event = Events.get_event_by_url(data["object"]["id"])
|
||||||
|
|
||||||
assert event.description == data["object"]["content"]
|
assert_enqueued(
|
||||||
end
|
worker: Mobilizon.Service.Workers.BuildSearch,
|
||||||
|
args: %{event_id: event_id, op: :update_search_event}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert %{success: 1, snoozed: 0, failure: 0} == Oban.drain_queue(queue: :search)
|
||||||
|
|
||||||
|
assert event.title == "My updated event"
|
||||||
|
|
||||||
|
assert event.description == data["object"]["content"]
|
||||||
end
|
end
|
||||||
|
|
||||||
# test "it works for incoming update activities which lock the account" do
|
# test "it works for incoming update activities which lock the account" do
|
||||||
|
|
|
@ -4,8 +4,6 @@
|
||||||
# Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/test/web/activity_pub/transmogrifier_test.exs
|
# Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/test/web/activity_pub/transmogrifier_test.exs
|
||||||
|
|
||||||
defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
|
defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
|
||||||
use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney
|
|
||||||
|
|
||||||
use Mobilizon.DataCase
|
use Mobilizon.DataCase
|
||||||
use Oban.Testing, repo: Mobilizon.Storage.Repo
|
use Oban.Testing, repo: Mobilizon.Storage.Repo
|
||||||
|
|
||||||
|
@ -33,54 +31,75 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
|
||||||
|
|
||||||
describe "handle incoming events" do
|
describe "handle incoming events" do
|
||||||
test "it works for incoming events" do
|
test "it works for incoming events" do
|
||||||
use_cassette "activity_pub/fetch_mobilizon_post_activity" do
|
actor_data = File.read!("test/fixtures/mastodon-actor.json") |> Jason.decode!()
|
||||||
data = File.read!("test/fixtures/mobilizon-post-activity.json") |> Jason.decode!()
|
|
||||||
|
|
||||||
{:ok, %Activity{data: data, local: false}, %Event{} = event} =
|
Mock
|
||||||
Transmogrifier.handle_incoming(data)
|
|> expect(:call, 2, fn
|
||||||
|
%{method: :get, url: url}, _opts ->
|
||||||
|
case url do
|
||||||
|
"https://mobilizon.fr/@metacartes" ->
|
||||||
|
actor_data = Map.put(actor_data, "id", "https://mobilizon.fr/@metacartes")
|
||||||
|
{:ok, %Tesla.Env{status: 200, body: actor_data}}
|
||||||
|
|
||||||
assert data["id"] ==
|
"https://framapiaf.org/users/tcit" ->
|
||||||
"https://mobilizon.fr/events/39a0c4a6-f2b6-41dc-bbe2-fc5bff76cc93/activity"
|
actor_data = Map.put(actor_data, "id", "https://framapiaf.org/users/tcit")
|
||||||
|
{:ok, %Tesla.Env{status: 200, body: actor_data}}
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
assert data["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
|
data = File.read!("test/fixtures/mobilizon-post-activity.json") |> Jason.decode!()
|
||||||
|
|
||||||
#
|
{:ok, %Activity{data: data, local: false}, %Event{} = event} =
|
||||||
# assert data["cc"] == [
|
Transmogrifier.handle_incoming(data)
|
||||||
# "https://framapiaf.org/users/admin/followers",
|
|
||||||
# "http://localtesting.pleroma.lol/users/lain"
|
|
||||||
# ]
|
|
||||||
|
|
||||||
assert data["actor"] == "https://mobilizon.fr/@metacartes"
|
assert data["id"] ==
|
||||||
|
"https://mobilizon.fr/events/39a0c4a6-f2b6-41dc-bbe2-fc5bff76cc93/activity"
|
||||||
|
|
||||||
object = data["object"]
|
assert data["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
|
||||||
|
|
||||||
assert object["id"] ==
|
#
|
||||||
"https://mobilizon.fr/events/39a0c4a6-f2b6-41dc-bbe2-fc5bff76cc93"
|
# assert data["cc"] == [
|
||||||
|
# "https://framapiaf.org/users/admin/followers",
|
||||||
|
# "http://localtesting.pleroma.lol/users/lain"
|
||||||
|
# ]
|
||||||
|
|
||||||
assert object["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
|
assert data["actor"] == "https://mobilizon.fr/@metacartes"
|
||||||
|
|
||||||
# assert object["cc"] == [
|
object = data["object"]
|
||||||
# "https://framapiaf.org/users/admin/followers",
|
|
||||||
# "http://localtesting.pleroma.lol/users/lain"
|
|
||||||
# ]
|
|
||||||
|
|
||||||
assert object["actor"] == "https://mobilizon.fr/@metacartes"
|
assert object["id"] ==
|
||||||
assert object["location"]["name"] == "Locaux de Framasoft"
|
"https://mobilizon.fr/events/39a0c4a6-f2b6-41dc-bbe2-fc5bff76cc93"
|
||||||
# assert object["attributedTo"] == "https://mobilizon.fr/@metacartes"
|
|
||||||
|
|
||||||
assert event.physical_address.street == "10 Rue Jangot"
|
assert object["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
|
||||||
|
|
||||||
assert event.physical_address.url ==
|
# assert object["cc"] == [
|
||||||
"https://event1.tcit.fr/address/eeecc11d-0030-43e8-a897-6422876372jd"
|
# "https://framapiaf.org/users/admin/followers",
|
||||||
|
# "http://localtesting.pleroma.lol/users/lain"
|
||||||
|
# ]
|
||||||
|
|
||||||
assert event.online_address == "https://google.com"
|
assert object["actor"] == "https://mobilizon.fr/@metacartes"
|
||||||
|
assert object["location"]["name"] == "Locaux de Framasoft"
|
||||||
|
# assert object["attributedTo"] == "https://mobilizon.fr/@metacartes"
|
||||||
|
|
||||||
{:ok, %Actor{}} = Actors.get_actor_by_url(object["actor"])
|
assert event.physical_address.street == "10 Rue Jangot"
|
||||||
end
|
|
||||||
|
assert event.physical_address.url ==
|
||||||
|
"https://event1.tcit.fr/address/eeecc11d-0030-43e8-a897-6422876372jd"
|
||||||
|
|
||||||
|
assert event.online_address == "https://google.com"
|
||||||
|
|
||||||
|
{:ok, %Actor{}} = Actors.get_actor_by_url(object["actor"])
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it works for incoming events from Gancio" do
|
test "it works for incoming events from Gancio" do
|
||||||
data = File.read!("test/fixtures/gancio-event-activity.json") |> Jason.decode!()
|
data = File.read!("test/fixtures/gancio-event-activity.json") |> Jason.decode!()
|
||||||
|
actor_data = File.read!("test/fixtures/gancio-actor.json") |> Jason.decode!()
|
||||||
|
|
||||||
|
Mock
|
||||||
|
|> expect(:call, fn
|
||||||
|
%{method: :get, url: "https://demo.gancio.org/federation/u/gancio"}, _opts ->
|
||||||
|
{:ok, %Tesla.Env{status: 200, body: actor_data}}
|
||||||
|
end)
|
||||||
|
|
||||||
{:ok, %Activity{data: data, local: false}, %Event{} = event} =
|
{:ok, %Activity{data: data, local: false}, %Event{} = event} =
|
||||||
Transmogrifier.handle_incoming(data)
|
Transmogrifier.handle_incoming(data)
|
||||||
|
@ -524,6 +543,12 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it accepts incoming resources and handles group being not found" do
|
test "it accepts incoming resources and handles group being not found" do
|
||||||
|
Mock
|
||||||
|
|> expect(:call, fn
|
||||||
|
%{method: :get, url: "https://someurl.com/notfound"}, _opts ->
|
||||||
|
{:ok, %Tesla.Env{status: 404, body: ""}}
|
||||||
|
end)
|
||||||
|
|
||||||
creator =
|
creator =
|
||||||
insert(:actor,
|
insert(:actor,
|
||||||
domain: "mobilizon.app",
|
domain: "mobilizon.app",
|
||||||
|
@ -649,12 +674,18 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
|
||||||
test "it works for incoming announces" do
|
test "it works for incoming announces" do
|
||||||
data = File.read!("test/fixtures/mastodon-announce.json") |> Jason.decode!()
|
data = File.read!("test/fixtures/mastodon-announce.json") |> Jason.decode!()
|
||||||
status_data = File.read!("test/fixtures/mastodon-status.json") |> Jason.decode!()
|
status_data = File.read!("test/fixtures/mastodon-status.json") |> Jason.decode!()
|
||||||
|
actor_data = File.read!("test/fixtures/mastodon-actor.json") |> Jason.decode!()
|
||||||
|
|
||||||
Mock
|
Mock
|
||||||
|> expect(:call, fn
|
|> expect(:call, 2, fn
|
||||||
%{method: :get, url: "https://framapiaf.org/users/peertube/statuses/104584600044284729"},
|
%{method: :get, url: url}, _opts ->
|
||||||
_opts ->
|
case url do
|
||||||
{:ok, %Tesla.Env{status: 200, body: status_data}}
|
"https://framapiaf.org/users/peertube/statuses/104584600044284729" ->
|
||||||
|
{:ok, %Tesla.Env{status: 200, body: status_data}}
|
||||||
|
|
||||||
|
"https://framapiaf.org/users/peertube" ->
|
||||||
|
{:ok, %Tesla.Env{status: 200, body: actor_data}}
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
{:ok, _, %Comment{actor: %Actor{url: actor_url}, url: comment_url}} =
|
{:ok, _, %Comment{actor: %Actor{url: actor_url}, url: comment_url}} =
|
||||||
|
@ -677,10 +708,12 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
|
||||||
File.read!("test/fixtures/mastodon-announce.json")
|
File.read!("test/fixtures/mastodon-announce.json")
|
||||||
|> Jason.decode!()
|
|> Jason.decode!()
|
||||||
|> Map.put("object", comment_url)
|
|> Map.put("object", comment_url)
|
||||||
|
|> Map.put("actor", actor_url)
|
||||||
|
|
||||||
Mock
|
Mock
|
||||||
|> expect(:call, fn
|
|> expect(:call, fn
|
||||||
%{method: :get, url: ^actor_url}, _opts ->
|
%{method: :get, url: ^actor_url}, _opts ->
|
||||||
|
actor_data = Map.put(actor_data, "id", actor_url)
|
||||||
{:ok, %Tesla.Env{status: 200, body: actor_data}}
|
{:ok, %Tesla.Env{status: 200, body: actor_data}}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
@ -926,10 +959,21 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
|
||||||
File.read!("test/fixtures/https__info.pleroma.site_activity.json")
|
File.read!("test/fixtures/https__info.pleroma.site_activity.json")
|
||||||
|> Jason.decode!()
|
|> Jason.decode!()
|
||||||
|
|
||||||
|
actor_data =
|
||||||
|
File.read!("test/fixtures/mastodon-actor.json")
|
||||||
|
|> Jason.decode!()
|
||||||
|
|> Map.put("id", "https://framapiaf.org/users/admin")
|
||||||
|
|
||||||
Mock
|
Mock
|
||||||
|> expect(:call, fn
|
|> expect(:call, 2, fn
|
||||||
%{method: :get, url: "https://info.pleroma.site/activity.json"}, _opts ->
|
%{method: :get, url: url}, _opts ->
|
||||||
{:ok, %Tesla.Env{status: 200, body: data}}
|
case url do
|
||||||
|
"https://info.pleroma.site/activity.json" ->
|
||||||
|
{:ok, %Tesla.Env{status: 200, body: data}}
|
||||||
|
|
||||||
|
"https://framapiaf.org/users/admin" ->
|
||||||
|
{:ok, %Tesla.Env{status: 200, body: actor_data}}
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
data = %{
|
data = %{
|
||||||
|
|
36
test/fixtures/gancio-actor.json
vendored
Normal file
36
test/fixtures/gancio-actor.json
vendored
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
{
|
||||||
|
"@context": [
|
||||||
|
"https://www.w3.org/ns/activitystreams",
|
||||||
|
"https://w3id.org/security/v1",
|
||||||
|
{
|
||||||
|
"toot": "http://joinmastodon.org/ns#",
|
||||||
|
"schema": "http://schema.org#",
|
||||||
|
"ProperyValue": "schema:PropertyValue",
|
||||||
|
"value": "schema:value"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "https://demo.gancio.org/federation/u/gancio",
|
||||||
|
"type": "Application",
|
||||||
|
"name": "gancio",
|
||||||
|
"preferredUsername": "gancio",
|
||||||
|
"inbox": "https://demo.gancio.org/federation/u/gancio/inbox",
|
||||||
|
"outbox": "https://demo.gancio.org/federation/u/gancio/outbox",
|
||||||
|
"discoverable": true,
|
||||||
|
"attachment": [
|
||||||
|
{
|
||||||
|
"type": "PropertyValue",
|
||||||
|
"name": "Website",
|
||||||
|
"value": "<a href='https://demo.gancio.org'>https://demo.gancio.org</a>"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"icon": {
|
||||||
|
"type": "Image",
|
||||||
|
"mediaType": "image/png",
|
||||||
|
"url": "https://demo.gancio.org/logo.png"
|
||||||
|
},
|
||||||
|
"publicKey": {
|
||||||
|
"id": "https://demo.gancio.org/federation/u/gancio#main-key",
|
||||||
|
"owner": "https://demo.gancio.org/federation/u/gancio",
|
||||||
|
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxp9BQ8TvVqu+0xXk7VuZ\nnuO42cHxVI+z/3TQ80AfX5aoUnK/uP7lIPy+NiIgRRu0L4hsjEs+HP6Ny9NAKFtC\nddS3pUrgIDz/AUyKeYRsCycw4XyeX7gaqIan4vCx+ANPDVTc3twDenynHhaXbPsP\nzGeKiAsGIFKRUxc5I5xnQBk6Fy6LZvGwfif07AcECER+nzffSOMPYFVbhlRuBwOg\n/tJcut77KOEpJIQSwqzT0FOw4oFtkvJt/nhpQMkXwOjEuiMOVpPoXUIpWjnbvNmy\nIPXdnKN4QqHi0fAE+FvKGbNmr18vqApT/D4Yen6W1ZWCRdUR1jjl8LNFBkPH/Tad\nkOj+UyRRJjRRqY5mXCI72Bmhwmi/YdS4gt9K73okOZ3atM+9Kfj3azZm8pP7fRkK\n/lwRP8RZFSSpz4w9JtzYmR7P8qTaxwMuq8VrxtFmf1IBChFpyNHUDtmC9MzLBRE7\n+fnpr1bARR3OwO83/xtT+vKNE+2SBvsf7zeFRXa+p5dGaih90rQOwL8EsUItiG61\nm4y9n3Q7BM7XwrZ7sGe3Hey5SWveOEgemfP4ANJBiMQpU69LKM9dGW1FcEX4FlwW\nZx/135nzMXE2cF+y+q/yY2FlacXPqJXMY32mIc+rHMzvFY/ZDzjRY/7Gg2ekjXuN\n1o7Ag7a+5k+r+XkWBNKIHp8CAwEAAQ==\n-----END PUBLIC KEY-----\n"
|
||||||
|
}
|
||||||
|
}
|
119
test/fixtures/mastodon-tcit-tcit.json
vendored
Normal file
119
test/fixtures/mastodon-tcit-tcit.json
vendored
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
{
|
||||||
|
"@context": [
|
||||||
|
"https://www.w3.org/ns/activitystreams",
|
||||||
|
"https://w3id.org/security/v1",
|
||||||
|
{
|
||||||
|
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
|
||||||
|
"toot": "http://joinmastodon.org/ns#",
|
||||||
|
"featured": {
|
||||||
|
"@id": "toot:featured",
|
||||||
|
"@type": "@id"
|
||||||
|
},
|
||||||
|
"featuredTags": {
|
||||||
|
"@id": "toot:featuredTags",
|
||||||
|
"@type": "@id"
|
||||||
|
},
|
||||||
|
"alsoKnownAs": {
|
||||||
|
"@id": "as:alsoKnownAs",
|
||||||
|
"@type": "@id"
|
||||||
|
},
|
||||||
|
"movedTo": {
|
||||||
|
"@id": "as:movedTo",
|
||||||
|
"@type": "@id"
|
||||||
|
},
|
||||||
|
"schema": "http://schema.org#",
|
||||||
|
"PropertyValue": "schema:PropertyValue",
|
||||||
|
"value": "schema:value",
|
||||||
|
"IdentityProof": "toot:IdentityProof",
|
||||||
|
"discoverable": "toot:discoverable",
|
||||||
|
"Device": "toot:Device",
|
||||||
|
"Ed25519Signature": "toot:Ed25519Signature",
|
||||||
|
"Ed25519Key": "toot:Ed25519Key",
|
||||||
|
"Curve25519Key": "toot:Curve25519Key",
|
||||||
|
"EncryptedMessage": "toot:EncryptedMessage",
|
||||||
|
"publicKeyBase64": "toot:publicKeyBase64",
|
||||||
|
"deviceId": "toot:deviceId",
|
||||||
|
"claim": {
|
||||||
|
"@type": "@id",
|
||||||
|
"@id": "toot:claim"
|
||||||
|
},
|
||||||
|
"fingerprintKey": {
|
||||||
|
"@type": "@id",
|
||||||
|
"@id": "toot:fingerprintKey"
|
||||||
|
},
|
||||||
|
"identityKey": {
|
||||||
|
"@type": "@id",
|
||||||
|
"@id": "toot:identityKey"
|
||||||
|
},
|
||||||
|
"devices": {
|
||||||
|
"@type": "@id",
|
||||||
|
"@id": "toot:devices"
|
||||||
|
},
|
||||||
|
"messageFranking": "toot:messageFranking",
|
||||||
|
"messageType": "toot:messageType",
|
||||||
|
"cipherText": "toot:cipherText",
|
||||||
|
"suspended": "toot:suspended",
|
||||||
|
"focalPoint": {
|
||||||
|
"@container": "@list",
|
||||||
|
"@id": "toot:focalPoint"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "https://social.tcit.fr/users/tcit",
|
||||||
|
"type": "Person",
|
||||||
|
"following": "https://social.tcit.fr/users/tcit/following",
|
||||||
|
"followers": "https://social.tcit.fr/users/tcit/followers",
|
||||||
|
"inbox": "https://social.tcit.fr/users/tcit/inbox",
|
||||||
|
"outbox": "https://social.tcit.fr/users/tcit/outbox",
|
||||||
|
"featured": "https://social.tcit.fr/users/tcit/collections/featured",
|
||||||
|
"featuredTags": "https://social.tcit.fr/users/tcit/collections/tags",
|
||||||
|
"preferredUsername": "tcit",
|
||||||
|
"name": "🦄 Thomas Citharel",
|
||||||
|
"summary": "<p>Hoping to make people's life better with free software at <span class=\"h-card\"><a href=\"https://framapiaf.org/@Framasoft\" class=\"u-url mention\">@<span>Framasoft</span></a></span>.</p><p>ᕕ(ᐛ)ᕗ</p>",
|
||||||
|
"url": "https://social.tcit.fr/@tcit",
|
||||||
|
"manuallyApprovesFollowers": false,
|
||||||
|
"discoverable": true,
|
||||||
|
"published": "2017-04-03T00:00:00Z",
|
||||||
|
"devices": "https://social.tcit.fr/users/tcit/collections/devices",
|
||||||
|
"publicKey": {
|
||||||
|
"id": "https://social.tcit.fr/users/tcit#main-key",
|
||||||
|
"owner": "https://social.tcit.fr/users/tcit",
|
||||||
|
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApXwYMUdFg3XUd+bGsh8C\nyiMRGpRGAWuCdM5pDWx5uM4pW2pM3xbHbcI21j9h8BmlAiPg6hbZD73KGly2N8Rt\n5iIS0I+l6i8kA1JCCdlAaDTRd41RKMggZDoQvjVZQtsyE1VzMeU2kbqqTFN6ew7H\nvbd6O0NhixoKoZ5f3jwuBDZoT0p1TAcaMdmG8oqHD97isizkDnRn8cOBA6wtI+xb\n5xP2zxZMsLpTDZLiKU8XcPKZCw4OfQfmDmKkHtrFb77jCAQj/s/FxjVnvxRwmfhN\nnWy0D+LUV/g63nHh/b5zXIeV92QZLvDYbgbezmzUzv9UeA1s70GGbaDqCIy85gw9\n+wIDAQAB\n-----END PUBLIC KEY-----\n"
|
||||||
|
},
|
||||||
|
"tag": [],
|
||||||
|
"attachment": [
|
||||||
|
{
|
||||||
|
"type": "PropertyValue",
|
||||||
|
"name": "Works at",
|
||||||
|
"value": "<span class=\"h-card\"><a href=\"https://framapiaf.org/@Framasoft\" class=\"u-url mention\">@<span>Framasoft@framapiaf.org</span></a></span>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "PropertyValue",
|
||||||
|
"name": "Pronouns",
|
||||||
|
"value": "He/Him"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "PropertyValue",
|
||||||
|
"name": "Work Account",
|
||||||
|
"value": "<a href=\"https://framapiaf.org/@tcit\" rel=\"me nofollow noopener noreferrer\" target=\"_blank\"><span class=\"invisible\">https://</span><span class=\"\">framapiaf.org/@tcit</span><span class=\"invisible\"></span></a>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "PropertyValue",
|
||||||
|
"name": "Site",
|
||||||
|
"value": "<a href=\"https://tcit.fr\" rel=\"me nofollow noopener noreferrer\" target=\"_blank\"><span class=\"invisible\">https://</span><span class=\"\">tcit.fr</span><span class=\"invisible\"></span></a>"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"endpoints": {
|
||||||
|
"sharedInbox": "https://social.tcit.fr/inbox"
|
||||||
|
},
|
||||||
|
"icon": {
|
||||||
|
"type": "Image",
|
||||||
|
"mediaType": "image/jpeg",
|
||||||
|
"url": "https://social.tcit.fr/system/accounts/avatars/000/000/001/original/a28c50ce5f2b13fd.jpg"
|
||||||
|
},
|
||||||
|
"image": {
|
||||||
|
"type": "Image",
|
||||||
|
"mediaType": "image/jpeg",
|
||||||
|
"url": "https://social.tcit.fr/system/accounts/headers/000/000/001/original/ac9c4a71083bd9a1.jpg"
|
||||||
|
}
|
||||||
|
}
|
112
test/fixtures/signature/framapiaf_admin.json
vendored
Normal file
112
test/fixtures/signature/framapiaf_admin.json
vendored
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
{
|
||||||
|
"@context": [
|
||||||
|
"https://www.w3.org/ns/activitystreams",
|
||||||
|
"https://w3id.org/security/v1",
|
||||||
|
{
|
||||||
|
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
|
||||||
|
"toot": "http://joinmastodon.org/ns#",
|
||||||
|
"featured": {
|
||||||
|
"@id": "toot:featured",
|
||||||
|
"@type": "@id"
|
||||||
|
},
|
||||||
|
"alsoKnownAs": {
|
||||||
|
"@id": "as:alsoKnownAs",
|
||||||
|
"@type": "@id"
|
||||||
|
},
|
||||||
|
"movedTo": {
|
||||||
|
"@id": "as:movedTo",
|
||||||
|
"@type": "@id"
|
||||||
|
},
|
||||||
|
"schema": "http://schema.org#",
|
||||||
|
"PropertyValue": "schema:PropertyValue",
|
||||||
|
"value": "schema:value",
|
||||||
|
"IdentityProof": "toot:IdentityProof",
|
||||||
|
"discoverable": "toot:discoverable",
|
||||||
|
"Device": "toot:Device",
|
||||||
|
"Ed25519Signature": "toot:Ed25519Signature",
|
||||||
|
"Ed25519Key": "toot:Ed25519Key",
|
||||||
|
"Curve25519Key": "toot:Curve25519Key",
|
||||||
|
"EncryptedMessage": "toot:EncryptedMessage",
|
||||||
|
"publicKeyBase64": "toot:publicKeyBase64",
|
||||||
|
"deviceId": "toot:deviceId",
|
||||||
|
"claim": {
|
||||||
|
"@type": "@id",
|
||||||
|
"@id": "toot:claim"
|
||||||
|
},
|
||||||
|
"fingerprintKey": {
|
||||||
|
"@type": "@id",
|
||||||
|
"@id": "toot:fingerprintKey"
|
||||||
|
},
|
||||||
|
"identityKey": {
|
||||||
|
"@type": "@id",
|
||||||
|
"@id": "toot:identityKey"
|
||||||
|
},
|
||||||
|
"devices": {
|
||||||
|
"@type": "@id",
|
||||||
|
"@id": "toot:devices"
|
||||||
|
},
|
||||||
|
"messageFranking": "toot:messageFranking",
|
||||||
|
"messageType": "toot:messageType",
|
||||||
|
"cipherText": "toot:cipherText",
|
||||||
|
"focalPoint": {
|
||||||
|
"@container": "@list",
|
||||||
|
"@id": "toot:focalPoint"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "https://framapiaf.org/users/admin",
|
||||||
|
"type": "Service",
|
||||||
|
"following": "https://framapiaf.org/users/admin/following",
|
||||||
|
"followers": "https://framapiaf.org/users/admin/followers",
|
||||||
|
"inbox": "https://framapiaf.org/users/admin/inbox",
|
||||||
|
"outbox": "https://framapiaf.org/users/admin/outbox",
|
||||||
|
"featured": "https://framapiaf.org/users/admin/collections/featured",
|
||||||
|
"preferredUsername": "admin",
|
||||||
|
"name": "Administrateur",
|
||||||
|
"summary": "<p>Je ne suis qu'un compte inutile. Merci nous de contacter via <a href=\"https://contact.framasoft.org/\" rel=\"nofollow noopener noreferrer\" target=\"_blank\"><span class=\"invisible\">https://</span><span class=\"\">contact.framasoft.org/</span><span class=\"invisible\"></span></a></p>",
|
||||||
|
"url": "https://framapiaf.org/@admin",
|
||||||
|
"manuallyApprovesFollowers": false,
|
||||||
|
"discoverable": null,
|
||||||
|
"devices": "https://framapiaf.org/users/admin/collections/devices",
|
||||||
|
"publicKey": {
|
||||||
|
"id": "https://framapiaf.org/users/admin#main-key",
|
||||||
|
"owner": "https://framapiaf.org/users/admin",
|
||||||
|
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyHaU/AZ5dWtSxZXkPa89\nDUQ4z+JQHGGUG/xkGuq0v8P6qJfQqtHPBO5vH0IQJqluXWQS96gqTwjZnYevcpNA\nveYv0K25DWszx5Ehz6JX2/sSvu2rNUcQ3YZvSjdo/Yy1u5Fuc5lLmvw8uFzXYekD\nWovTMOnp4mIKpVEm/G/v4w8jvFEKw88h743vwaEIim88GEQItMxzGAV6zSqV1DWO\nLxtoRsinslJYfAG46ex4YUATFveWvOUeWk5W1sEa5f3c0moaTmBM/PAAo8vLxhlw\nJhsHihsCH+BcXKVMjW8OCqYYqISMxEifUBX63HcJt78ELHpOuc1c2eG59PomtTjQ\nywIDAQAB\n-----END PUBLIC KEY-----\n"
|
||||||
|
},
|
||||||
|
"tag": [],
|
||||||
|
"attachment": [
|
||||||
|
{
|
||||||
|
"type": "PropertyValue",
|
||||||
|
"name": "News",
|
||||||
|
"value": "<span class=\"h-card\"><a href=\"https://framapiaf.org/@Framasoft\" class=\"u-url mention\">@<span>Framasoft</span></a></span>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "PropertyValue",
|
||||||
|
"name": "Support",
|
||||||
|
"value": "<a href=\"https://contact.framasoft.org/\" rel=\"me nofollow noopener noreferrer\" target=\"_blank\"><span class=\"invisible\">https://</span><span class=\"\">contact.framasoft.org/</span><span class=\"invisible\"></span></a>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "PropertyValue",
|
||||||
|
"name": "Soutenir",
|
||||||
|
"value": "<a href=\"https://soutenir.framasoft.org/\" rel=\"me nofollow noopener noreferrer\" target=\"_blank\"><span class=\"invisible\">https://</span><span class=\"\">soutenir.framasoft.org/</span><span class=\"invisible\"></span></a>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "PropertyValue",
|
||||||
|
"name": "Site",
|
||||||
|
"value": "<a href=\"https://framasoft.org/\" rel=\"me nofollow noopener noreferrer\" target=\"_blank\"><span class=\"invisible\">https://</span><span class=\"\">framasoft.org/</span><span class=\"invisible\"></span></a>"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"endpoints": {
|
||||||
|
"sharedInbox": "https://framapiaf.org/inbox"
|
||||||
|
},
|
||||||
|
"icon": {
|
||||||
|
"type": "Image",
|
||||||
|
"mediaType": "image/jpeg",
|
||||||
|
"url": "https://framapiaf.s3.framasoft.org/framapiaf/accounts/avatars/000/000/002/original/85fbb27ad5e3cf71.jpg"
|
||||||
|
},
|
||||||
|
"image": {
|
||||||
|
"type": "Image",
|
||||||
|
"mediaType": "image/jpeg",
|
||||||
|
"url": "https://framapiaf.s3.framasoft.org/framapiaf/accounts/headers/000/000/002/original/6aba75f1ab1ab6de.jpg"
|
||||||
|
}
|
||||||
|
}
|
55
test/fixtures/signature/nyu_rye.json
vendored
Normal file
55
test/fixtures/signature/nyu_rye.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
{
|
||||||
|
"@context": [
|
||||||
|
"https://www.w3.org/ns/activitystreams",
|
||||||
|
"https://w3id.org/security/v1",
|
||||||
|
{
|
||||||
|
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
|
||||||
|
"toot": "http://joinmastodon.org/ns#",
|
||||||
|
"featured": { "@id": "toot:featured", "@type": "@id" },
|
||||||
|
"alsoKnownAs": { "@id": "as:alsoKnownAs", "@type": "@id" },
|
||||||
|
"movedTo": { "@id": "as:movedTo", "@type": "@id" },
|
||||||
|
"schema": "http://schema.org#",
|
||||||
|
"PropertyValue": "schema:PropertyValue",
|
||||||
|
"value": "schema:value",
|
||||||
|
"IdentityProof": "toot:IdentityProof",
|
||||||
|
"discoverable": "toot:discoverable",
|
||||||
|
"Device": "toot:Device",
|
||||||
|
"Ed25519Signature": "toot:Ed25519Signature",
|
||||||
|
"Ed25519Key": "toot:Ed25519Key",
|
||||||
|
"Curve25519Key": "toot:Curve25519Key",
|
||||||
|
"EncryptedMessage": "toot:EncryptedMessage",
|
||||||
|
"publicKeyBase64": "toot:publicKeyBase64",
|
||||||
|
"deviceId": "toot:deviceId",
|
||||||
|
"claim": { "@type": "@id", "@id": "toot:claim" },
|
||||||
|
"fingerprintKey": { "@type": "@id", "@id": "toot:fingerprintKey" },
|
||||||
|
"identityKey": { "@type": "@id", "@id": "toot:identityKey" },
|
||||||
|
"devices": { "@type": "@id", "@id": "toot:devices" },
|
||||||
|
"messageFranking": "toot:messageFranking",
|
||||||
|
"messageType": "toot:messageType",
|
||||||
|
"cipherText": "toot:cipherText",
|
||||||
|
"focalPoint": { "@container": "@list", "@id": "toot:focalPoint" }
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "https://niu.moe/users/rye",
|
||||||
|
"type": "Person",
|
||||||
|
"following": "https://niu.moe/users/rye/following",
|
||||||
|
"followers": "https://niu.moe/users/rye/followers",
|
||||||
|
"inbox": "https://niu.moe/users/rye/inbox",
|
||||||
|
"outbox": "https://niu.moe/users/rye/outbox",
|
||||||
|
"featured": "https://niu.moe/users/rye/collections/featured",
|
||||||
|
"preferredUsername": "rye",
|
||||||
|
"name": "♡ rye ♡",
|
||||||
|
"summary": "\\u003cp\\u003ecome back with a warrant\\u003c/p\\u003e",
|
||||||
|
"url": "https://niu.moe/@rye",
|
||||||
|
"manuallyApprovesFollowers": false,
|
||||||
|
"discoverable": false,
|
||||||
|
"devices": "https://niu.moe/users/rye/collections/devices",
|
||||||
|
"publicKey": {
|
||||||
|
"id": "https://niu.moe/users/rye#main-key",
|
||||||
|
"owner": "https://niu.moe/users/rye",
|
||||||
|
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA83uRWjCFO35FwfA38mzv\\nEL0TUaXB7+2hYvPwNrn1WY6me5DRbqB5zzMrzWMGr0HSooqNqEYBafGsmVTWUqIk\\nKM9ehtIBraJI+mT5X7DPR3LrXOJF4a9EEslg8XvAk8MN9IrAhm6UljnvB67RtDcA\\nTNB01VWy9yWnxFRtz9o/EMoBPyw5giOaXE2ibVNP8lQIqGKuuBKPzPjSJygdvQ5q\\nxfow2z1TpKRqdsNDqn4n6U6zCXYTzkr0J71/tGw7fsgfv78l0Wjrc7EcuBk74OaG\\nC65UDiu3X4Q6kxCfCEhPSfuwLN+UZkzxcn6goWR0iYpWs57+4tFKu9nJYP4QJ0K9\\nTwIDAQAB\\n-----END PUBLIC KEY-----\\n"
|
||||||
|
},
|
||||||
|
"tag": [],
|
||||||
|
"attachment": [],
|
||||||
|
"endpoints": { "sharedInbox": "https://niu.moe/inbox" }
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,20 +1,19 @@
|
||||||
defmodule Mobilizon.ActorsTest do
|
defmodule Mobilizon.ActorsTest do
|
||||||
use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney
|
|
||||||
use Mobilizon.DataCase
|
use Mobilizon.DataCase
|
||||||
use Oban.Testing, repo: Mobilizon.Storage.Repo
|
use Oban.Testing, repo: Mobilizon.Storage.Repo
|
||||||
|
|
||||||
|
import Mox
|
||||||
import Mobilizon.Factory
|
import Mobilizon.Factory
|
||||||
|
|
||||||
alias Mobilizon.{Actors, Config, Discussions, Events, Users}
|
alias Mobilizon.{Actors, Config, Discussions, Events, Users}
|
||||||
alias Mobilizon.Actors.{Actor, Bot, Follower, Member}
|
alias Mobilizon.Actors.{Actor, Bot, Follower, Member}
|
||||||
alias Mobilizon.Discussions.Comment
|
alias Mobilizon.Discussions.Comment
|
||||||
alias Mobilizon.Events.Event
|
alias Mobilizon.Events.Event
|
||||||
|
alias Mobilizon.Federation.ActivityPub.Actor, as: ActivityPubActor
|
||||||
alias Mobilizon.Medias.File, as: FileModel
|
alias Mobilizon.Medias.File, as: FileModel
|
||||||
|
alias Mobilizon.Service.HTTP.ActivityPub.Mock
|
||||||
alias Mobilizon.Service.Workers
|
alias Mobilizon.Service.Workers
|
||||||
alias Mobilizon.Storage.Page
|
alias Mobilizon.Storage.Page
|
||||||
|
|
||||||
alias Mobilizon.Federation.ActivityPub.Actor, as: ActivityPubActor
|
|
||||||
|
|
||||||
alias Mobilizon.Web.Upload.Uploader
|
alias Mobilizon.Web.Upload.Uploader
|
||||||
|
|
||||||
describe "actors" do
|
describe "actors" do
|
||||||
|
@ -99,25 +98,32 @@ defmodule Mobilizon.ActorsTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "get_actor_by_name/1 returns a remote actor" do
|
test "get_actor_by_name/1 returns a remote actor" do
|
||||||
use_cassette "actors/remote_actor_mastodon_tcit" do
|
tcit_social_tcit =
|
||||||
{:ok,
|
"test/fixtures/mastodon-tcit-tcit.json" |> File.read!() |> Jason.decode!()
|
||||||
%Actor{
|
|
||||||
id: actor_id,
|
|
||||||
preferred_username: preferred_username,
|
|
||||||
domain: domain,
|
|
||||||
avatar: %FileModel{name: picture_name} = _picture
|
|
||||||
} = _actor} = ActivityPubActor.get_or_fetch_actor_by_url(@remote_account_url)
|
|
||||||
|
|
||||||
assert picture_name == "a28c50ce5f2b13fd.jpg"
|
Mock
|
||||||
|
|> expect(:call, fn
|
||||||
|
%{method: :get, url: @remote_account_url}, _opts ->
|
||||||
|
{:ok, %Tesla.Env{status: 200, body: tcit_social_tcit}}
|
||||||
|
end)
|
||||||
|
|
||||||
%Actor{
|
{:ok,
|
||||||
id: actor_found_id,
|
%Actor{
|
||||||
avatar: %FileModel{name: picture_name} = _picture
|
id: actor_id,
|
||||||
} = Actors.get_actor_by_name("#{preferred_username}@#{domain}")
|
preferred_username: preferred_username,
|
||||||
|
domain: domain,
|
||||||
|
avatar: %FileModel{name: picture_name} = _picture
|
||||||
|
} = _actor} = ActivityPubActor.get_or_fetch_actor_by_url(@remote_account_url)
|
||||||
|
|
||||||
assert actor_found_id == actor_id
|
assert picture_name == "a28c50ce5f2b13fd.jpg"
|
||||||
assert picture_name == "a28c50ce5f2b13fd.jpg"
|
|
||||||
end
|
%Actor{
|
||||||
|
id: actor_found_id,
|
||||||
|
avatar: %FileModel{name: picture_name} = _picture
|
||||||
|
} = Actors.get_actor_by_name("#{preferred_username}@#{domain}")
|
||||||
|
|
||||||
|
assert actor_found_id == actor_id
|
||||||
|
assert picture_name == "a28c50ce5f2b13fd.jpg"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "get_local_actor_by_name_with_preload!/1 returns the local actor with its organized events",
|
test "get_local_actor_by_name_with_preload!/1 returns the local actor with its organized events",
|
||||||
|
@ -155,22 +161,29 @@ defmodule Mobilizon.ActorsTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "get_actor_by_name_with_preload!/1 returns the remote actor with its organized events" do
|
test "get_actor_by_name_with_preload!/1 returns the remote actor with its organized events" do
|
||||||
use_cassette "actors/remote_actor_mastodon_tcit" do
|
tcit_social_tcit =
|
||||||
with {:ok, %Actor{} = actor} <-
|
"test/fixtures/mastodon-tcit-tcit.json" |> File.read!() |> Jason.decode!()
|
||||||
ActivityPubActor.get_or_fetch_actor_by_url(@remote_account_url) do
|
|
||||||
assert Actors.get_actor_by_name_with_preload(
|
|
||||||
"#{actor.preferred_username}@#{actor.domain}"
|
|
||||||
).organized_events == []
|
|
||||||
|
|
||||||
event = insert(:event, organizer_actor: actor)
|
Mock
|
||||||
|
|> expect(:call, fn
|
||||||
|
%{method: :get, url: @remote_account_url}, _opts ->
|
||||||
|
{:ok, %Tesla.Env{status: 200, body: tcit_social_tcit}}
|
||||||
|
end)
|
||||||
|
|
||||||
event_found_id =
|
with {:ok, %Actor{} = actor} <-
|
||||||
Actors.get_actor_by_name_with_preload("#{actor.preferred_username}@#{actor.domain}").organized_events
|
ActivityPubActor.get_or_fetch_actor_by_url(@remote_account_url) do
|
||||||
|> hd
|
assert Actors.get_actor_by_name_with_preload(
|
||||||
|> Map.get(:id)
|
"#{actor.preferred_username}@#{actor.domain}"
|
||||||
|
).organized_events == []
|
||||||
|
|
||||||
assert event_found_id == event.id
|
event = insert(:event, organizer_actor: actor)
|
||||||
end
|
|
||||||
|
event_found_id =
|
||||||
|
Actors.get_actor_by_name_with_preload("#{actor.preferred_username}@#{actor.domain}").organized_events
|
||||||
|
|> hd
|
||||||
|
|> Map.get(:id)
|
||||||
|
|
||||||
|
assert event_found_id == event.id
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -185,19 +198,26 @@ defmodule Mobilizon.ActorsTest do
|
||||||
|
|
||||||
test "test search_actors/4 returns actors with similar usernames",
|
test "test search_actors/4 returns actors with similar usernames",
|
||||||
%{actor: %Actor{id: actor_id}} do
|
%{actor: %Actor{id: actor_id}} do
|
||||||
use_cassette "actors/remote_actor_mastodon_tcit" do
|
tcit_social_tcit =
|
||||||
with {:ok, %Actor{id: actor2_id}} <-
|
"test/fixtures/mastodon-tcit-tcit.json" |> File.read!() |> Jason.decode!()
|
||||||
ActivityPubActor.get_or_fetch_actor_by_url(@remote_account_url) do
|
|
||||||
%Page{total: 2, elements: actors} =
|
|
||||||
Actors.search_actors("tcit",
|
|
||||||
actor_type: :Person,
|
|
||||||
minimum_visibility: :private
|
|
||||||
)
|
|
||||||
|
|
||||||
actors_ids = actors |> Enum.map(& &1.id)
|
Mock
|
||||||
|
|> expect(:call, fn
|
||||||
|
%{method: :get, url: @remote_account_url}, _opts ->
|
||||||
|
{:ok, %Tesla.Env{status: 200, body: tcit_social_tcit}}
|
||||||
|
end)
|
||||||
|
|
||||||
assert MapSet.new(actors_ids) == MapSet.new([actor2_id, actor_id])
|
with {:ok, %Actor{id: actor2_id}} <-
|
||||||
end
|
ActivityPubActor.get_or_fetch_actor_by_url(@remote_account_url) do
|
||||||
|
%Page{total: 2, elements: actors} =
|
||||||
|
Actors.search_actors("tcit",
|
||||||
|
actor_type: :Person,
|
||||||
|
minimum_visibility: :private
|
||||||
|
)
|
||||||
|
|
||||||
|
actors_ids = actors |> Enum.map(& &1.id)
|
||||||
|
|
||||||
|
assert MapSet.new(actors_ids) == MapSet.new([actor2_id, actor_id])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -120,7 +120,6 @@ defmodule Mobilizon.Web.ActivityPubControllerTest do
|
||||||
|
|
||||||
describe "/@:preferred_username/inbox" do
|
describe "/@:preferred_username/inbox" do
|
||||||
test "it inserts an incoming event into the database", %{conn: conn} do
|
test "it inserts an incoming event into the database", %{conn: conn} do
|
||||||
# use_cassette "activity_pub_controller/mastodon-post-activity_actor_call" do
|
|
||||||
data = File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!()
|
data = File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!()
|
||||||
|
|
||||||
%Actor{url: remote_actor_url} =
|
%Actor{url: remote_actor_url} =
|
||||||
|
@ -151,6 +150,9 @@ defmodule Mobilizon.Web.ActivityPubControllerTest do
|
||||||
^local_actor_url ->
|
^local_actor_url ->
|
||||||
{:ok, %Tesla.Env{status: 200, body: local_actor_data}}
|
{:ok, %Tesla.Env{status: 200, body: local_actor_data}}
|
||||||
|
|
||||||
|
"https://framapiaf.org/users/tcit" ->
|
||||||
|
{:ok, %Tesla.Env{status: 404, body: ""}}
|
||||||
|
|
||||||
"https://framapiaf.org/users/admin/statuses/99512778738411822" ->
|
"https://framapiaf.org/users/admin/statuses/99512778738411822" ->
|
||||||
{:ok, %Tesla.Env{status: 404, body: ""}}
|
{:ok, %Tesla.Env{status: 404, body: ""}}
|
||||||
end
|
end
|
||||||
|
@ -168,7 +170,6 @@ defmodule Mobilizon.Web.ActivityPubControllerTest do
|
||||||
ActivityPub.fetch_object_from_url(data["object"]["id"])
|
ActivityPub.fetch_object_from_url(data["object"]["id"])
|
||||||
|
|
||||||
assert comment.actor.id == remote_actor.id
|
assert comment.actor.id == remote_actor.id
|
||||||
# end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
|
|
||||||
defmodule Mobilizon.Web.Plugs.MappedSignatureToIdentityTest do
|
defmodule Mobilizon.Web.Plugs.MappedSignatureToIdentityTest do
|
||||||
use Mobilizon.Web.ConnCase
|
use Mobilizon.Web.ConnCase
|
||||||
use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney
|
import Mox
|
||||||
|
|
||||||
|
alias Mobilizon.Service.HTTP.ActivityPub.Mock
|
||||||
alias Mobilizon.Web.Plugs.MappedSignatureToIdentity
|
alias Mobilizon.Web.Plugs.MappedSignatureToIdentity
|
||||||
|
|
||||||
defp set_signature(conn, key_id) do
|
defp set_signature(conn, key_id) do
|
||||||
|
@ -15,47 +16,100 @@ defmodule Mobilizon.Web.Plugs.MappedSignatureToIdentityTest do
|
||||||
|> assign(:valid_signature, true)
|
|> assign(:valid_signature, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it successfully maps a valid identity with a valid signature" do
|
defp framapiaf_admin do
|
||||||
use_cassette "activity_pub/signature/valid" do
|
"test/fixtures/signature/framapiaf_admin.json"
|
||||||
conn =
|
|> File.read!()
|
||||||
build_conn(:get, "/doesntmattter")
|
|> Jason.decode!()
|
||||||
|> set_signature("https://framapiaf.org/users/admin")
|
end
|
||||||
|> MappedSignatureToIdentity.call(%{})
|
|
||||||
|
|
||||||
refute is_nil(conn.assigns.actor)
|
defp nyu_rye do
|
||||||
end
|
"test/fixtures/signature/nyu_rye.json"
|
||||||
|
|> File.read!()
|
||||||
|
|> Jason.decode!()
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it successfully maps a valid identity with a valid signature" do
|
||||||
|
Mock
|
||||||
|
|> expect(:call, fn
|
||||||
|
%{method: :get, url: "https://framapiaf.org/users/admin"}, _opts ->
|
||||||
|
{:ok, %Tesla.Env{status: 200, body: framapiaf_admin()}}
|
||||||
|
end)
|
||||||
|
|
||||||
|
Mock
|
||||||
|
|> expect(:call, fn
|
||||||
|
%{method: :get, url: "/doesntmattter"}, _opts ->
|
||||||
|
{:ok, %Tesla.Env{status: 200, body: ""}}
|
||||||
|
end)
|
||||||
|
|
||||||
|
conn =
|
||||||
|
build_conn(:get, "/doesntmattter")
|
||||||
|
|> set_signature("https://framapiaf.org/users/admin")
|
||||||
|
|> MappedSignatureToIdentity.call(%{})
|
||||||
|
|
||||||
|
refute is_nil(conn.assigns.actor)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it successfully maps a valid identity with a valid signature with payload" do
|
test "it successfully maps a valid identity with a valid signature with payload" do
|
||||||
use_cassette "activity_pub/signature/valid_payload" do
|
Mock
|
||||||
conn =
|
|> expect(:call, fn
|
||||||
build_conn(:post, "/doesntmattter", %{"actor" => "https://framapiaf.org/users/admin"})
|
%{method: :get, url: "https://framapiaf.org/users/admin"}, _opts ->
|
||||||
|> set_signature("https://framapiaf.org/users/admin")
|
{:ok, %Tesla.Env{status: 200, body: framapiaf_admin()}}
|
||||||
|> MappedSignatureToIdentity.call(%{})
|
end)
|
||||||
|
|
||||||
refute is_nil(conn.assigns.actor)
|
Mock
|
||||||
end
|
|> expect(:call, fn
|
||||||
|
%{method: :post, url: "/doesntmattter"}, _opts ->
|
||||||
|
{:ok, %Tesla.Env{status: 200, body: ""}}
|
||||||
|
end)
|
||||||
|
|
||||||
|
conn =
|
||||||
|
build_conn(:post, "/doesntmattter", %{"actor" => "https://framapiaf.org/users/admin"})
|
||||||
|
|> set_signature("https://framapiaf.org/users/admin")
|
||||||
|
|> MappedSignatureToIdentity.call(%{})
|
||||||
|
|
||||||
|
refute is_nil(conn.assigns.actor)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it considers a mapped identity to be invalid when it mismatches a payload" do
|
test "it considers a mapped identity to be invalid when it mismatches a payload" do
|
||||||
use_cassette "activity_pub/signature/invalid_payload" do
|
Mock
|
||||||
conn =
|
|> expect(:call, fn
|
||||||
build_conn(:post, "/doesntmattter", %{"actor" => "https://framapiaf.org/users/admin"})
|
%{method: :get, url: "https://niu.moe/users/rye"}, _opts ->
|
||||||
|> set_signature("https://niu.moe/users/rye")
|
{:ok, %Tesla.Env{status: 200, body: nyu_rye()}}
|
||||||
|> MappedSignatureToIdentity.call(%{})
|
end)
|
||||||
|
|
||||||
assert %{valid_signature: false} == conn.assigns
|
Mock
|
||||||
end
|
|> expect(:call, fn
|
||||||
|
%{method: :post, url: "/doesntmattter"}, _opts ->
|
||||||
|
{:ok, %Tesla.Env{status: 200, body: ""}}
|
||||||
|
end)
|
||||||
|
|
||||||
|
conn =
|
||||||
|
build_conn(:post, "/doesntmattter", %{"actor" => "https://framapiaf.org/users/admin"})
|
||||||
|
|> set_signature("https://niu.moe/users/rye")
|
||||||
|
|> MappedSignatureToIdentity.call(%{})
|
||||||
|
|
||||||
|
assert %{valid_signature: false} == conn.assigns
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@tag skip: "Available again when lib/web/plugs/mapped_signature_to_identity.ex#62 is fixed"
|
||||||
test "it considers a mapped identity to be invalid when the identity cannot be found" do
|
test "it considers a mapped identity to be invalid when the identity cannot be found" do
|
||||||
use_cassette "activity_pub/signature/invalid_not_found" do
|
Mock
|
||||||
conn =
|
|> expect(:call, fn
|
||||||
build_conn(:post, "/doesntmattter", %{"actor" => "https://framapiaf.org/users/admin"})
|
%{method: :get, url: "https://mastodon.social/users/gargron"}, _opts ->
|
||||||
|> set_signature("https://mastodon.social/users/gargron")
|
{:ok, %Tesla.Env{status: 404, body: ""}}
|
||||||
|> MappedSignatureToIdentity.call(%{})
|
end)
|
||||||
|
|
||||||
assert %{valid_signature: false} == conn.assigns
|
Mock
|
||||||
end
|
|> expect(:call, fn
|
||||||
|
%{method: :post, url: "/doesntmattter"}, _opts ->
|
||||||
|
{:ok, %Tesla.Env{status: 200, body: ""}}
|
||||||
|
end)
|
||||||
|
|
||||||
|
conn =
|
||||||
|
build_conn(:post, "/doesntmattter", %{"actor" => "https://framapiaf.org/users/admin"})
|
||||||
|
|> set_signature("https://mastodon.social/users/gargron")
|
||||||
|
|> MappedSignatureToIdentity.call(%{})
|
||||||
|
|
||||||
|
assert %{valid_signature: false} == conn.assigns
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue