diff --git a/lib/mobilizon/activity.ex b/lib/mobilizon/activity.ex index 354291e12..2bcdc4fed 100644 --- a/lib/mobilizon/activity.ex +++ b/lib/mobilizon/activity.ex @@ -3,5 +3,5 @@ defmodule Mobilizon.Activity do Represents an activity """ - defstruct [:id, :data, :local, :actor, :recipients, :notifications, :type] + defstruct [:data, :local, :actor, :recipients, :notifications] end diff --git a/lib/mobilizon/actors/actor.ex b/lib/mobilizon/actors/actor.ex index c4f5f5238..80e7445cd 100644 --- a/lib/mobilizon/actors/actor.ex +++ b/lib/mobilizon/actors/actor.ex @@ -131,7 +131,6 @@ defmodule Mobilizon.Actors.Actor do :outbox_url, :inbox_url, :type, - :name, :domain, :preferred_username, :keys @@ -179,17 +178,38 @@ defmodule Mobilizon.Actors.Actor do |> put_change(:local, true) end + @doc """ + Get a public key for a given ActivityPub actor ID (url) + """ @spec get_public_key_for_url(String.t()) :: {:ok, String.t()} def get_public_key_for_url(url) do - with {:ok, %Actor{} = actor} <- Actors.get_or_fetch_by_url(url) do - {:ok, actor.keys} + with {:ok, %Actor{keys: keys}} <- Actors.get_or_fetch_by_url(url), + {:ok, public_key} <- prepare_public_key(keys) do + {:ok, public_key} else + {:error, :pem_decode_error} -> + Logger.error("Error while decoding PEM") + {:error, :pem_decode_error} + _ -> Logger.error("Unable to fetch actor, so no keys for you") {:error, :actor_fetch_error} end end + @doc """ + Convert internal PEM encoded keys to public key format + """ + @spec prepare_public_key(String.t()) :: {:ok, tuple()} | {:error, :pem_decode_error} + def prepare_public_key(public_key_code) do + with [public_key_entry] <- :public_key.pem_decode(public_key_code) do + {:ok, :public_key.pem_entry_decode(public_key_entry)} + else + _err -> + {:error, :pem_decode_error} + end + end + @doc """ Get followers from an actor diff --git a/lib/mobilizon/actors/actors.ex b/lib/mobilizon/actors/actors.ex index 427661ef4..b8781a792 100644 --- a/lib/mobilizon/actors/actors.ex +++ b/lib/mobilizon/actors/actors.ex @@ -6,7 +6,7 @@ defmodule Mobilizon.Actors do import Ecto.Query, warn: false alias Mobilizon.Repo - alias Mobilizon.Actors.Actor + alias Mobilizon.Actors.{Actor, Bot, Member, Follower, User} alias Mobilizon.Actors alias Mobilizon.Service.ActivityPub @@ -24,10 +24,11 @@ defmodule Mobilizon.Actors do ## Examples - iex> list_actors() - [%Actor{}, ...] + iex> Mobilizon.Actors.list_actors() + [%Mobilizon.Actors.Actor{}] """ + @spec list_actors() :: list() def list_actors do Repo.all(Actor) end @@ -40,12 +41,13 @@ defmodule Mobilizon.Actors do ## Examples iex> get_actor!(123) - %Actor{} + %Mobilizon.Actors.Actor{} iex> get_actor!(456) ** (Ecto.NoResultsError) """ + @spec get_actor!(integer()) :: Actor.t() def get_actor!(id) do Repo.get!(Actor, id) end @@ -53,7 +55,7 @@ defmodule Mobilizon.Actors do @doc """ Returns the associated actor for an user, either the default set one or the first found """ - @spec get_actor_for_user(%Mobilizon.Actors.User{}) :: %Mobilizon.Actors.Actor{} + @spec get_actor_for_user(Mobilizon.Actors.User.t()) :: Mobilizon.Actors.Actor.t() def get_actor_for_user(%Mobilizon.Actors.User{} = user) do case user.default_actor_id do nil -> get_first_actor_for_user(user) @@ -82,10 +84,10 @@ defmodule Mobilizon.Actors do ## Examples - iex> create_actor(%{field: value}) - {:ok, %Actor{}} + iex> create_actor(%{preferred_username: "test"}) + {:ok, %Mobilizon.Actors.Actor{preferred_username: "test"}} - iex> create_actor(%{field: bad_value}) + iex> create_actor(%{preferred_username: nil}) {:error, %Ecto.Changeset{}} """ @@ -100,10 +102,10 @@ defmodule Mobilizon.Actors do ## Examples - iex> update_actor(actor, %{field: new_value}) - {:ok, %Actor{}} + iex> update_actor(%Actor{preferred_username: "toto"}, %{preferred_username: "tata"}) + {:ok, %Mobilizon.Actors.Actor{preferred_username: "tata"}} - iex> update_actor(actor, %{field: bad_value}) + iex> update_actor(%Actor{preferred_username: "toto"}, %{preferred_username: nil}) {:error, %Ecto.Changeset{}} """ @@ -118,13 +120,14 @@ defmodule Mobilizon.Actors do ## Examples - iex> delete_actor(actor) - {:ok, %Actor{}} + iex> delete_actor(%Actor{}) + {:ok, %Mobilizon.Actors.Actor{}} - iex> delete_actor(actor) + iex> delete_actor(nil) {:error, %Ecto.Changeset{}} """ + @spec delete_actor(Actor.t()) :: {:ok, Actor.t()} | {:error, Ecto.Changeset.t()} def delete_actor(%Actor{} = actor) do Repo.delete(actor) end @@ -134,8 +137,8 @@ defmodule Mobilizon.Actors do ## Examples - iex> change_actor(actor) - %Ecto.Changeset{source: %Actor{}} + iex> change_actor(%Actor{}) + %Ecto.Changeset{data: %Mobilizon.Actors.Actor{}} """ def change_actor(%Actor{} = actor) do @@ -164,10 +167,10 @@ defmodule Mobilizon.Actors do ## Examples - iex> create_group(%{field: value}) - {:ok, %Actor{}} + iex> create_group(%{name: "group name"}) + {:ok, %Mobilizon.Actors.Actor{}} - iex> create_group(%{field: bad_value}) + iex> create_group(%{name: nil}) {:error, %Ecto.Changeset{}} """ @@ -185,28 +188,20 @@ defmodule Mobilizon.Actors do ## Examples iex> list_users() - [%User{}, ...] + [%Mobilizon.Actors.User{}] """ def list_users do Repo.all(User) end - @doc """ - List users with their associated actors. No reason for that, so removed - """ - # def list_users_with_actors do - # users = Repo.all(User) - # Repo.preload(users, :actors) - # end - defp blank?(""), do: nil defp blank?(n), do: n def insert_or_update_actor(data, preload \\ false) do cs = Actor.remote_actor_creation(data) - actor = + {:ok, actor} = Repo.insert( cs, on_conflict: [ @@ -249,7 +244,7 @@ defmodule Mobilizon.Actors do ## Examples iex> get_user!(123) - %User{} + %Mobilizon.Actors.User{} iex> get_user!(456) ** (Ecto.NoResultsError) @@ -257,13 +252,19 @@ defmodule Mobilizon.Actors do """ def get_user!(id), do: Repo.get!(User, id) - def get_user_with_actor!(id) do + @doc """ + Get an user with it's actors + + Raises `Ecto.NoResultsError` if the User does not exist. + """ + @spec get_user_with_actors!(integer()) :: User.t() + def get_user_with_actors!(id) do user = Repo.get!(User, id) Repo.preload(user, :actors) end - @spec get_user_with_actor(integer()) :: %User{} - def get_user_with_actor(id) do + @spec get_user_with_actors(integer()) :: User.t() + def get_user_with_actors(id) do case Repo.get(User, id) do nil -> {:error, "User with ID #{id} not found"} user -> {:ok, Repo.preload(user, :actors)} @@ -271,9 +272,22 @@ defmodule Mobilizon.Actors do end @doc """ - Get an actor by it's URL (ActivityPub ID) + Get an actor by it's URL (ActivityPub ID). The `:preload` option allows preloading the Followers relation. + + Raises `Ecto.NoResultsError` if the Actor does not exist. + + ## Examples + iex> get_actor_by_url("https://mastodon.server.tld/users/user") + {:ok, %Mobilizon.Actors.Actor{preferred_username: "user"}} + + iex> get_actor_by_url("https://mastodon.server.tld/users/user", true) + {:ok, %Mobilizon.Actors.Actor{preferred_username: "user", followers: []}} + + iex> get_actor_by_url("non existent") + {:error, :actor_not_found} + """ - @spec get_actor_by_url(String.t(), boolean()) :: {:ok, struct()} | {:error, :actor_not_found} + @spec get_actor_by_url(String.t(), boolean()) :: {:ok, Actor.t()} | {:error, :actor_not_found} def get_actor_by_url(url, preload \\ false) do case Repo.get_by(Actor, url: url) do nil -> @@ -284,6 +298,22 @@ defmodule Mobilizon.Actors do end end + @doc """ + Get an actor by it's URL (ActivityPub ID). The `:preload` option allows preloading the Followers relation. + + Raises `Ecto.NoResultsError` if the Actor does not exist. + + ## Examples + iex> get_actor_by_url!("https://mastodon.server.tld/users/user") + %Mobilizon.Actors.Actor{} + + iex> get_actor_by_url!("https://mastodon.server.tld/users/user", true) + {:ok, %Mobilizon.Actors.Actor{preferred_username: "user", followers: []}} + + iex> get_actor_by_url!("non existent") + ** (Ecto.NoResultsError) + + """ @spec get_actor_by_url!(String.t(), boolean()) :: struct() def get_actor_by_url!(url, preload \\ false) do actor = Repo.get_by!(Actor, url: url) @@ -324,16 +354,32 @@ defmodule Mobilizon.Actors do end def get_or_fetch_by_url(url, preload \\ false) do - if {:ok, actor} = get_actor_by_url(url, preload) do + with {:ok, actor} <- get_actor_by_url(url, preload) do {:ok, actor} else - case ActivityPub.make_actor_from_url(url, preload) do - {:ok, actor} -> - {:ok, actor} + _ -> + case ActivityPub.make_actor_from_url(url, preload) do + {:ok, actor} -> + {:ok, actor} - _ -> - {:error, "Could not fetch by AP id"} - end + _ -> + {:error, "Could not fetch by AP id"} + end + end + end + + def get_or_fetch_by_url!(url, preload \\ false) do + with {:ok, actor} <- get_actor_by_url(url, preload) do + actor + else + _ -> + case ActivityPub.make_actor_from_url(url, preload) do + {:ok, actor} -> + actor + + _ -> + raise "Could not fetch by AP id" + end end end @@ -503,10 +549,10 @@ defmodule Mobilizon.Actors do ## Examples - iex> create_user(%{field: value}) - {:ok, %User{}} + iex> create_user(%{email: "test@test.tld"}) + {:ok, %Mobilizon.Actors.User{}} - iex> create_user(%{field: bad_value}) + iex> create_user(%{email: "not an email"}) {:error, %Ecto.Changeset{}} """ @@ -521,11 +567,11 @@ defmodule Mobilizon.Actors do ## Examples - iex> get_user_by_email(user, email) - {:ok, %User{}} + iex> get_user_by_email("test@test.tld", true) + {:ok, %Mobilizon.Actors.User{}} - iex> get_user_by_email(user, wrong_email) - {:error, nil} + iex> get_user_by_email("test@notfound.tld", false) + {:error, :user_not_found} """ def get_user_by_email(email, activated \\ nil) do query = @@ -546,10 +592,10 @@ defmodule Mobilizon.Actors do ## Examples - iex> update_user(user, %{field: new_value}) - {:ok, %User{}} + iex> update_user(User{}, %{password: "coucou"}) + {:ok, %Mobilizon.Actors.User{}} - iex> update_user(user, %{field: bad_value}) + iex> update_user(User{}, %{password: nil}) {:error, %Ecto.Changeset{}} """ @@ -564,10 +610,10 @@ defmodule Mobilizon.Actors do ## Examples - iex> delete_user(user) - {:ok, %User{}} + iex> delete_user(%User{email: "test@test.tld"}) + {:ok, %Mobilizon.Actors.User{}} - iex> delete_user(user) + iex> delete_user(%User{}) {:error, %Ecto.Changeset{}} """ @@ -580,8 +626,8 @@ defmodule Mobilizon.Actors do ## Examples - iex> change_user(user) - %Ecto.Changeset{source: %User{}} + iex> change_user(%Mobilizon.Actors.User{}) + %Ecto.Changeset{data: %Mobilizon.Actors.User{}} """ def change_user(%User{} = user) do @@ -598,7 +644,7 @@ defmodule Mobilizon.Actors do ## Examples iex> get_member!(123) - %Member{} + %Mobilizon.Actors.Member{} iex> get_member!(456) ** (Ecto.NoResultsError) @@ -611,10 +657,10 @@ defmodule Mobilizon.Actors do ## Examples - iex> create_member(%{field: value}) - {:ok, %Member{}} + iex> create_member(%{actor: %Actor{}}) + {:ok, %Mobilizon.Actors.Member{}} - iex> create_member(%{field: bad_value}) + iex> create_member(%{actor: nil}) {:error, %Ecto.Changeset{}} """ @@ -632,10 +678,10 @@ defmodule Mobilizon.Actors do ## Examples - iex> update_member(member, %{field: new_value}) - {:ok, %Member{}} + iex> update_member(%Member{}, %{role: 3}) + {:ok, %Mobilizon.Actors.Member{}} - iex> update_member(member, %{field: bad_value}) + iex> update_member(%Member{}, %{role: nil}) {:error, %Ecto.Changeset{}} """ @@ -650,10 +696,10 @@ defmodule Mobilizon.Actors do ## Examples - iex> delete_member(member) - {:ok, %Member{}} + iex> delete_member(%Member{}) + {:ok, %Mobilizon.Actors.Member{}} - iex> delete_member(member) + iex> delete_member(%Member{}) {:error, %Ecto.Changeset{}} """ @@ -666,8 +712,8 @@ defmodule Mobilizon.Actors do ## Examples - iex> change_member(member) - %Ecto.Changeset{source: %Member{}} + iex> change_member(%Member{}) + %Ecto.Changeset{data: %Mobilizon.Actors.Member{}} """ def change_member(%Member{} = member) do @@ -702,7 +748,7 @@ defmodule Mobilizon.Actors do ## Examples iex> list_bots() - [%Bot{}, ...] + [%Mobilizon.Actors.Bot{}] """ def list_bots do @@ -717,7 +763,7 @@ defmodule Mobilizon.Actors do ## Examples iex> get_bot!(123) - %Bot{} + %Mobilizon.Actors.Bot{} iex> get_bot!(456) ** (Ecto.NoResultsError) @@ -735,10 +781,10 @@ defmodule Mobilizon.Actors do ## Examples - iex> create_bot(%{field: value}) - {:ok, %Bot{}} + iex> create_bot(%{source: "toto"}) + {:ok, %Mobilizon.Actors.Bot{}} - iex> create_bot(%{field: bad_value}) + iex> create_bot(%{source: nil}) {:error, %Ecto.Changeset{}} """ @@ -753,10 +799,10 @@ defmodule Mobilizon.Actors do ## Examples - iex> update_bot(bot, %{field: new_value}) - {:ok, %Bot{}} + iex> update_bot(%Bot{}, %{source: "new"}) + {:ok, %Mobilizon.Actors.Bot{}} - iex> update_bot(bot, %{field: bad_value}) + iex> update_bot(%Bot{}, %{source: nil}) {:error, %Ecto.Changeset{}} """ @@ -771,10 +817,10 @@ defmodule Mobilizon.Actors do ## Examples - iex> delete_bot(bot) - {:ok, %Bot{}} + iex> delete_bot(%Bot{}) + {:ok, %Mobilizon.Actors.Bot{}} - iex> delete_bot(bot) + iex> delete_bot(%Bot{}) {:error, %Ecto.Changeset{}} """ @@ -787,8 +833,8 @@ defmodule Mobilizon.Actors do ## Examples - iex> change_bot(bot) - %Ecto.Changeset{source: %Bot{}} + iex> change_bot(%Bot{}) + %Ecto.Changeset{data: %Mobilizon.Actors.Bot{}} """ def change_bot(%Bot{} = bot) do @@ -805,7 +851,7 @@ defmodule Mobilizon.Actors do ## Examples iex> get_follower!(123) - %Follower{} + %Mobilizon.Actors.Follower{} iex> get_follower!(456) ** (Ecto.NoResultsError) @@ -821,10 +867,10 @@ defmodule Mobilizon.Actors do ## Examples - iex> create_follower(%{field: value}) - {:ok, %Follower{}} + iex> create_follower(%{actor: %Actor{}}) + {:ok, %Mobilizon.Actors.Follower{}} - iex> create_follower(%{field: bad_value}) + iex> create_follower(%{actor: nil}) {:error, %Ecto.Changeset{}} """ @@ -839,10 +885,10 @@ defmodule Mobilizon.Actors do ## Examples - iex> update_follower(follower, %{field: new_value}) - {:ok, %Follower{}} + iex> update_follower(Follower{}, %{approved: true}) + {:ok, %Mobilizon.Actors.Follower{}} - iex> update_follower(follower, %{field: bad_value}) + iex> update_follower(Follower{}, %{approved: nil}) {:error, %Ecto.Changeset{}} """ @@ -857,10 +903,10 @@ defmodule Mobilizon.Actors do ## Examples - iex> delete_follower(follower) - {:ok, %Follower{}} + iex> delete_follower(Follower{}) + {:ok, %Mobilizon.Actors.Follower{}} - iex> delete_follower(follower) + iex> delete_follower(Follower{}) {:error, %Ecto.Changeset{}} """ @@ -873,8 +919,8 @@ defmodule Mobilizon.Actors do ## Examples - iex> change_follower(follower) - %Ecto.Changeset{source: %Follower{}} + iex> change_follower(Follower{}) + %Ecto.Changeset{data: %Mobilizon.Actors.Follower{}} """ def change_follower(%Follower{} = follower) do diff --git a/lib/mobilizon/actors/service/tools.ex b/lib/mobilizon/actors/service/tools.ex index 52634254d..4c6e9aef0 100644 --- a/lib/mobilizon/actors/service/tools.ex +++ b/lib/mobilizon/actors/service/tools.ex @@ -1,7 +1,7 @@ defmodule Mobilizon.Actors.Service.Tools do alias Mobilizon.Actors.User - @spec we_can_send_email(User.t()) :: boolean + @spec we_can_send_email(User.t(), atom()) :: :ok | {:error, :email_too_soon} def we_can_send_email(%User{} = user, key \\ :reset_password_sent_at) do case Map.get(user, key) do nil -> diff --git a/lib/mobilizon/events/events.ex b/lib/mobilizon/events/events.ex index a2c5b63d4..323b8b283 100644 --- a/lib/mobilizon/events/events.ex +++ b/lib/mobilizon/events/events.ex @@ -142,7 +142,7 @@ defmodule Mobilizon.Events do Gets an event by it's URL """ def get_event_full_by_url!(url) do - event = Repo.get_by(Event, url: url) + event = Repo.get_by!(Event, url: url) Repo.preload(event, [ :organizer_actor, @@ -326,7 +326,7 @@ defmodule Mobilizon.Events do """ def get_category!(id), do: Repo.get!(Category, id) - @spec get_category_by_title(String.t()) :: tuple() + @spec get_category_by_title(String.t()) :: Category.t() | nil def get_category_by_title(title) when is_binary(title) do Repo.get_by(Category, title: title) end diff --git a/lib/mobilizon_web/controllers/activity_pub_controller.ex b/lib/mobilizon_web/controllers/activity_pub_controller.ex index 65b806d06..cb5f865bd 100644 --- a/lib/mobilizon_web/controllers/activity_pub_controller.ex +++ b/lib/mobilizon_web/controllers/activity_pub_controller.ex @@ -4,6 +4,7 @@ defmodule MobilizonWeb.ActivityPubController do alias Mobilizon.Events.{Event, Comment} alias MobilizonWeb.ActivityPub.{ObjectView, ActorView} alias Mobilizon.Service.ActivityPub + alias Mobilizon.Service.ActivityPub.Utils alias Mobilizon.Service.Federator require Logger @@ -46,7 +47,7 @@ defmodule MobilizonWeb.ActivityPubController do true <- event.public do conn |> put_resp_header("content-type", "application/activity+json") - |> json(ObjectView.render("event.json", %{event: event})) + |> json(ObjectView.render("event.json", %{event: event |> Utils.make_event_data()})) else _ -> {:error, :not_found} @@ -60,7 +61,7 @@ defmodule MobilizonWeb.ActivityPubController do # true <- comment.public do conn |> put_resp_header("content-type", "application/activity+json") - |> json(ObjectView.render("comment.json", %{comment: comment})) + |> json(ObjectView.render("comment.json", %{comment: comment |> Utils.make_comment_data()})) else _ -> {:error, :not_found} @@ -137,11 +138,11 @@ defmodule MobilizonWeb.ActivityPubController do headers = Enum.into(conn.req_headers, %{}) if String.contains?(headers["signature"], params["actor"]) do - Logger.info( + Logger.error( "Signature validation error for: #{params["actor"]}, make sure you are forwarding the HTTP Host header!" ) - Logger.info(inspect(conn.req_headers)) + Logger.error(inspect(conn.req_headers)) end json(conn, "error") diff --git a/lib/mobilizon_web/guardian.ex b/lib/mobilizon_web/guardian.ex index 944618218..3d02c3d43 100644 --- a/lib/mobilizon_web/guardian.ex +++ b/lib/mobilizon_web/guardian.ex @@ -24,7 +24,7 @@ defmodule MobilizonWeb.Guardian do try do case Integer.parse(uid_str) do {uid, ""} -> - {:ok, Actors.get_user_with_actor!(uid)} + {:ok, Actors.get_user_with_actors!(uid)} _ -> {:error, :invalid_id} diff --git a/lib/mobilizon_web/http_signature.ex b/lib/mobilizon_web/http_signature.ex index 5858cdfec..e3c33513a 100644 --- a/lib/mobilizon_web/http_signature.ex +++ b/lib/mobilizon_web/http_signature.ex @@ -18,34 +18,31 @@ defmodule MobilizonWeb.HTTPSignaturePlug do end def call(conn, _opts) do - user = conn.params["actor"] + actor = conn.params["actor"] Logger.debug(fn -> - "Checking sig for #{user}" + "Checking sig for #{actor}" end) - with [signature | _] <- get_req_header(conn, "signature") do - cond do - signature && String.contains?(signature, user) -> - conn = - conn - |> put_req_header( - "(request-target)", - String.downcase("#{conn.method}") <> " #{conn.request_path}" - ) + [signature | _] = get_req_header(conn, "signature") - assign(conn, :valid_signature, HTTPSignatures.validate_conn(conn)) - - signature -> - Logger.debug("Signature not from actor") - assign(conn, :valid_signature, false) - - true -> - Logger.debug("No signature header!") + cond do + # Dialyzer doesn't like this line + signature && String.contains?(signature, actor) -> + conn = conn - end - else - _ -> + |> put_req_header( + "(request-target)", + String.downcase("#{conn.method}") <> " #{conn.request_path}" + ) + + assign(conn, :valid_signature, HTTPSignatures.validate_conn(conn)) + + signature -> + Logger.debug("Signature not from actor") + assign(conn, :valid_signature, false) + + true -> Logger.debug("No signature header!") conn end diff --git a/lib/mobilizon_web/resolvers/user.ex b/lib/mobilizon_web/resolvers/user.ex index d56a88e5b..3940acd9b 100644 --- a/lib/mobilizon_web/resolvers/user.ex +++ b/lib/mobilizon_web/resolvers/user.ex @@ -6,7 +6,7 @@ defmodule MobilizonWeb.Resolvers.User do Find an user by it's ID """ def find_user(_parent, %{id: id}, _resolution) do - Actors.get_user_with_actor(id) + Actors.get_user_with_actors(id) end @doc """ diff --git a/lib/mobilizon_web/router.ex b/lib/mobilizon_web/router.ex index c40e6774f..8dde8992b 100644 --- a/lib/mobilizon_web/router.ex +++ b/lib/mobilizon_web/router.ex @@ -13,11 +13,15 @@ defmodule MobilizonWeb.Router do plug(:accepts, ["json", "jrd-json"]) end - pipeline :activity_pub do + pipeline :activity_pub_signature do plug(:accepts, ["activity-json", "html"]) plug(MobilizonWeb.HTTPSignaturePlug) end + pipeline :activity_pub do + plug(:accepts, ["activity-json", "html"]) + end + pipeline :browser do plug(:accepts, ["html"]) plug(:fetch_session) @@ -56,6 +60,10 @@ defmodule MobilizonWeb.Router do get("/@:name/followers", ActivityPubController, :followers) get("/events/:uuid", ActivityPubController, :event) get("/comments/:uuid", ActivityPubController, :comment) + end + + scope "/", MobilizonWeb do + pipe_through(:activity_pub_signature) post("/@:name/inbox", ActivityPubController, :inbox) post("/inbox", ActivityPubController, :inbox) end diff --git a/lib/mobilizon_web/schema.ex b/lib/mobilizon_web/schema.ex index e60067c2d..972a44911 100644 --- a/lib/mobilizon_web/schema.ex +++ b/lib/mobilizon_web/schema.ex @@ -309,10 +309,10 @@ defmodule MobilizonWeb.Schema do resolve(&Resolvers.User.change_default_actor/3) end - @desc "Upload a picture" - field :upload_picture, :picture do - arg(:file, non_null(:upload)) - resolve(&Resolvers.Upload.upload_picture/3) - end + # @desc "Upload a picture" + # field :upload_picture, :picture do + # arg(:file, non_null(:upload)) + # resolve(&Resolvers.Upload.upload_picture/3) + # end end end diff --git a/lib/mobilizon_web/views/activity_pub/actor_view.ex b/lib/mobilizon_web/views/activity_pub/actor_view.ex index 6a94747bb..68b47257f 100644 --- a/lib/mobilizon_web/views/activity_pub/actor_view.ex +++ b/lib/mobilizon_web/views/activity_pub/actor_view.ex @@ -97,11 +97,11 @@ defmodule MobilizonWeb.ActivityPub.ActorView do {activities, total} = ActivityPub.fetch_public_activities_for_actor(actor, page) - collection = - Enum.map(activities, fn act -> - {:ok, data} = Transmogrifier.prepare_outgoing(act.data) - data - end) + # collection = + # Enum.map(activities, fn act -> + # {:ok, data} = Transmogrifier.prepare_outgoing(act.data) + # data + # end) iri = "#{actor.url}/outbox" @@ -127,9 +127,9 @@ defmodule MobilizonWeb.ActivityPub.ActorView do end end - def render("activity.json", %{activity: %Activity{local: local} = activity}) do + def render("activity.json", %{activity: %Activity{local: local, data: data} = activity}) do %{ - "id" => activity.data.url <> "/activity", + "id" => data["id"], "type" => if local do "Create" @@ -139,14 +139,14 @@ defmodule MobilizonWeb.ActivityPub.ActorView do "actor" => activity.actor, # Not sure if needed since this is used into outbox "published" => Timex.now(), - "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "to" => activity.recipients, "object" => - case activity.type do - :Event -> - render_one(activity.data, ObjectView, "event.json", as: :event) + case data["type"] do + "Event" -> + render_one(data, ObjectView, "event.json", as: :event) - :Comment -> - render_one(activity.data, ObjectView, "comment.json", as: :comment) + "Note" -> + render_one(data, ObjectView, "comment.json", as: :comment) end } |> Map.merge(Utils.make_json_ld_header()) diff --git a/lib/mobilizon_web/views/activity_pub/object_view.ex b/lib/mobilizon_web/views/activity_pub/object_view.ex index 83ccab60d..01260de81 100644 --- a/lib/mobilizon_web/views/activity_pub/object_view.ex +++ b/lib/mobilizon_web/views/activity_pub/object_view.ex @@ -7,13 +7,14 @@ defmodule MobilizonWeb.ActivityPub.ObjectView do def render("event.json", %{event: event}) do event = %{ "type" => "Event", - "id" => event.url, - "name" => event.title, - "category" => render_one(event.category, ObjectView, "category.json", as: :category), - "content" => event.description, - "mediaType" => "text/html", - "published" => Timex.format!(event.inserted_at, "{ISO:Extended}"), - "updated" => Timex.format!(event.updated_at, "{ISO:Extended}") + "actor" => event["actor"], + "id" => event["id"], + "name" => event["title"], + "category" => render_one(event["category"], ObjectView, "category.json", as: :category), + "content" => event["summary"], + "mediaType" => "text/html" + # "published" => Timex.format!(event.inserted_at, "{ISO:Extended}"), + # "updated" => Timex.format!(event.updated_at, "{ISO:Extended}") } Map.merge(event, Utils.make_json_ld_header()) @@ -21,16 +22,16 @@ defmodule MobilizonWeb.ActivityPub.ObjectView do def render("comment.json", %{comment: comment}) do comment = %{ - "actor" => comment.actor.url, - "uuid" => comment.uuid, + "actor" => comment["actor"], + "uuid" => comment["uuid"], # The activity should have attributedTo, not the comment itself # "attributedTo" => comment.attributed_to, "type" => "Note", - "id" => comment.url, - "content" => comment.text, - "mediaType" => "text/html", - "published" => Timex.format!(comment.inserted_at, "{ISO:Extended}"), - "updated" => Timex.format!(comment.updated_at, "{ISO:Extended}") + "id" => comment["id"], + "content" => comment["content"], + "mediaType" => "text/html" + # "published" => Timex.format!(comment.inserted_at, "{ISO:Extended}"), + # "updated" => Timex.format!(comment.updated_at, "{ISO:Extended}") } Map.merge(comment, Utils.make_json_ld_header()) diff --git a/lib/service/activity_pub/activity_pub.ex b/lib/service/activity_pub/activity_pub.ex index db4466aa7..4b6d6c31d 100644 --- a/lib/service/activity_pub/activity_pub.ex +++ b/lib/service/activity_pub/activity_pub.ex @@ -19,14 +19,21 @@ defmodule Mobilizon.Service.ActivityPub do require Logger import Mobilizon.Service.ActivityPub.Utils + @doc """ + Get recipients for an activity or object + """ + @spec get_recipients(map()) :: list() def get_recipients(data) do (data["to"] || []) ++ (data["cc"] || []) end - def insert(map, local \\ true) when is_map(map) do - Logger.debug("preparing an activity") - Logger.debug(inspect(map)) + @doc """ + Wraps an object into an activity + TODO: Rename me + """ + @spec insert(map(), boolean()) :: {:ok, %Activity{}} | {:error, any()} + def insert(map, local \\ true) when is_map(map) do with map <- lazy_put_activity_defaults(map), :ok <- insert_full_object(map, local) do object_id = @@ -56,10 +63,10 @@ defmodule Mobilizon.Service.ActivityPub do end end - def fetch_object_from_url(url, :event), do: fetch_event_from_url(url) - def fetch_object_from_url(url, :note), do: fetch_note_from_url(url) - - @spec fetch_object_from_url(String.t()) :: tuple() + @doc """ + Fetch an object from an URL, from our local database of events and comments, then eventually remote + """ + @spec fetch_object_from_url(String.t()) :: {:ok, %Event{}} | {:ok, %Comment{}} | {:error, any()} def fetch_object_from_url(url) do with true <- String.starts_with?(url, "http"), nil <- Events.get_event_by_url(url), @@ -95,29 +102,6 @@ defmodule Mobilizon.Service.ActivityPub do end end - @spec fetch_object_from_url(String.t()) :: tuple() - def fetch_event_from_url(url) do - with nil <- Events.get_event_by_url(url) do - Logger.info("Fetching #{url} via AP") - fetch_object_from_url(url) - else - %Event{} = comment -> - {:ok, comment} - end - end - - @spec fetch_object_from_url(String.t()) :: tuple() - def fetch_note_from_url(url) do - with nil <- Events.get_comment_from_url(url) do - Logger.info("Fetching #{url} via AP") - - fetch_object_from_url(url) - else - %Comment{} = comment -> - {:ok, comment} - end - end - def create(%{to: to, actor: actor, object: object} = params) do Logger.debug("creating an activity") additional = params[:additional] || %{} @@ -136,8 +120,8 @@ defmodule Mobilizon.Service.ActivityPub do {:ok, activity} else err -> - Logger.debug("Something went wrong") - Logger.debug(inspect(err)) + Logger.error("Something went wrong") + Logger.error(inspect(err)) end end @@ -216,6 +200,10 @@ defmodule Mobilizon.Service.ActivityPub do def create_public_activities(%Actor{} = actor) do end + @doc """ + Create an actor locally by it's URL (AP ID) + """ + @spec make_actor_from_url(String.t(), boolean()) :: {:ok, %Actor{}} | {:error, any()} def make_actor_from_url(url, preload \\ false) do with {:ok, data} <- fetch_and_prepare_actor_from_url(url) do Actors.insert_or_update_actor(data, preload) @@ -231,6 +219,9 @@ defmodule Mobilizon.Service.ActivityPub do end end + @doc """ + Find an actor in our local database or call Webfinger to find what's its AP ID is and then fetch it + """ @spec find_or_make_actor_from_nickname(String.t()) :: tuple() def find_or_make_actor_from_nickname(nickname) do with %Actor{} = actor <- Actors.get_actor_by_name(nickname) do @@ -240,6 +231,10 @@ defmodule Mobilizon.Service.ActivityPub do end end + @doc """ + Create an actor inside our database from username, using Webfinger to find out it's AP ID and then fetch it + """ + @spec make_actor_from_nickname(String.t()) :: {:ok, %Actor{}} | {:error, any()} def make_actor_from_nickname(nickname) do with {:ok, %{"url" => url}} when not is_nil(url) <- WebFinger.finger(nickname) do make_actor_from_url(url) @@ -288,12 +283,6 @@ defmodule Mobilizon.Service.ActivityPub do "content-length": byte_size(json) }) - Logger.debug("signature") - Logger.debug(inspect(signature)) - - Logger.debug("body json") - Logger.debug(inspect(json)) - {:ok, response} = HTTPoison.post( inbox, @@ -301,19 +290,21 @@ defmodule Mobilizon.Service.ActivityPub do [{"Content-Type", "application/activity+json"}, {"signature", signature}], hackney: [pool: :default] ) - - Logger.debug(inspect(response)) end - def fetch_and_prepare_actor_from_url(url) do + @doc """ + Fetching a remote actor's informations through it's AP ID + """ + @spec fetch_and_prepare_actor_from_url(String.t()) :: {:ok, struct()} | {:error, atom()} | any() + defp fetch_and_prepare_actor_from_url(url) do Logger.debug("Fetching and preparing actor from url") with {:ok, %HTTPoison.Response{status_code: 200, body: body}} <- HTTPoison.get(url, [Accept: "application/activity+json"], follow_redirect: true), {:ok, data} <- Jason.decode(body) do - user_data_from_user_object(data) + actor_data_from_actor_object(data) else - # User is gone, probably deleted + # Actor is gone, probably deleted {:ok, %HTTPoison.Response{status_code: 410}} -> {:error, :actor_deleted} @@ -323,8 +314,12 @@ defmodule Mobilizon.Service.ActivityPub do end end - def user_data_from_user_object(data) do - user_data = %{ + @doc """ + Creating proper actor data struct from AP data + """ + @spec actor_data_from_actor_object(map()) :: {:ok, map()} + def actor_data_from_actor_object(data) when is_map(data) do + actor_data = %{ url: data["id"], info: %{ "ap_enabled" => true, @@ -347,30 +342,22 @@ defmodule Mobilizon.Service.ActivityPub do type: data["type"] } - Logger.debug("user_data_from_user_object") - Logger.debug(inspect(user_data)) - - {:ok, user_data} + {:ok, actor_data} end - @spec fetch_public_activities_for_actor(Actor.t(), integer(), integer()) :: list() + @doc """ + Return all public activities (events & comments) for an actor + """ + @spec fetch_public_activities_for_actor(Actor.t(), integer(), integer()) :: {list(), integer()} def fetch_public_activities_for_actor(%Actor{} = actor, page \\ 1, limit \\ 10) do case actor.type do :Person -> {:ok, events, total} = Events.get_events_for_actor(actor, page, limit) {:ok, comments, total} = Events.get_comments_for_actor(actor, page, limit) - event_activities = - Enum.map(events, fn event -> - {:ok, activity} = event_to_activity(event) - activity - end) + event_activities = Enum.map(events, &event_to_activity/1) - comment_activities = - Enum.map(comments, fn comment -> - {:ok, activity} = comment_to_activity(comment) - activity - end) + comment_activities = Enum.map(comments, &comment_to_activity/1) activities = event_activities ++ comment_activities @@ -402,37 +389,36 @@ defmodule Mobilizon.Service.ActivityPub do end end + @doc """ + Create an activity from an event + """ + @spec event_to_activity(%Event{}, boolean()) :: Activity.t() defp event_to_activity(%Event{} = event, local \\ true) do - activity = %Activity{ - type: :Event, - data: event, - local: local, + %Activity{ + recipients: ["https://www.w3.org/ns/activitystreams#Public"], actor: event.organizer_actor.url, - recipients: ["https://www.w3.org/ns/activitystreams#Public"] + data: event |> make_event_data, + local: local } - - # Notification.create_notifications(activity) - # stream_out(activity) - {:ok, activity} end + @doc """ + Create an activity from a comment + """ + @spec comment_to_activity(%Comment{}, boolean()) :: Activity.t() defp comment_to_activity(%Comment{} = comment, local \\ true) do - activity = %Activity{ - type: :Comment, - data: comment, - local: local, + %Activity{ + recipients: ["https://www.w3.org/ns/activitystreams#Public"], actor: comment.actor.url, - recipients: ["https://www.w3.org/ns/activitystreams#Public"] + data: comment |> make_comment_data, + local: local } - - # Notification.create_notifications(activity) - # stream_out(activity) - {:ok, activity} end defp ical_event_to_activity(%ExIcal.Event{} = ical_event, %Actor{} = actor, source) do # Logger.debug(inspect ical_event) # TODO : refactor me ! + # TODO : also, there should be a form of cache that allows this to be more efficient category = if is_nil(ical_event.categories) do nil diff --git a/lib/service/activity_pub/transmogrifier.ex b/lib/service/activity_pub/transmogrifier.ex index 1c2a99c42..a9e615864 100644 --- a/lib/service/activity_pub/transmogrifier.ex +++ b/lib/service/activity_pub/transmogrifier.ex @@ -26,13 +26,16 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do when not is_nil(in_reply_to) do in_reply_to_id = cond do - is_bitstring(in_reply_to) -> # If the inReplyTo is just an AP ID + # If the inReplyTo is just an AP ID + is_bitstring(in_reply_to) -> in_reply_to - is_map(in_reply_to) && is_bitstring(in_reply_to["id"]) -> # If the inReplyTo is a object itself + # If the inReplyTo is a object itself + is_map(in_reply_to) && is_bitstring(in_reply_to["id"]) -> in_reply_to["id"] - is_list(in_reply_to) && is_bitstring(Enum.at(in_reply_to, 0)) -> # If the inReplyTo is an array + # If the inReplyTo is an array + is_list(in_reply_to) && is_bitstring(Enum.at(in_reply_to, 0)) -> Enum.at(in_reply_to, 0) true -> @@ -44,7 +47,7 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do case fetch_obj_helper(in_reply_to_id) do {:ok, replied_object} -> object - |> Map.put("inReplyTo", replied_object.data["id"]) + |> Map.put("inReplyTo", replied_object.url) e -> Logger.error("Couldn't fetch #{in_reply_to_id} #{inspect(e)}") @@ -128,7 +131,7 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do # ) do # with %User{} = actor <- User.get_or_fetch_by_ap_id(actor), # {:ok, object} <- - # get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id), + # fetch_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id), # {:ok, activity, object} <- ActivityPub.like(actor, object, id, false) do # {:ok, activity} # else @@ -136,18 +139,18 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do # end # end # - def handle_incoming( - %{"type" => "Announce", "object" => object_id, "actor" => actor, "id" => id} = data - ) do - with {:ok, %Actor{} = actor} <- Actors.get_or_fetch_by_url(actor), - {:ok, object} <- - get_obj_helper(object_id) || ActivityPub.fetch_event_from_url(object_id), - {:ok, activity, object} <- ActivityPub.announce(actor, object, id, false) do - {:ok, activity} - else - _e -> :error - end - end + # def handle_incoming( + # %{"type" => "Announce", "object" => object_id, "actor" => actor, "id" => id} = data + # ) do + # with {:ok, %Actor{} = actor} <- Actors.get_or_fetch_by_url(actor), + # {:ok, object} <- + # fetch_obj_helper(object_id) || ActivityPub.fetch_object_from_url(object_id), + # {:ok, activity, object} <- ActivityPub.announce(actor, object, id, false) do + # {:ok, activity} + # else + # _e -> :error + # end + # end # # def handle_incoming( @@ -155,7 +158,7 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do # data # ) do # with %User{ap_id: ^actor_id} = actor <- User.get_by_ap_id(object["id"]) do - # {:ok, new_user_data} = ActivityPub.user_data_from_user_object(object) + # {:ok, new_user_data} = ActivityPub.actor_data_from_actor_object(object) # # banner = new_user_data[:info]["banner"] # @@ -194,7 +197,7 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do # # with %User{} = actor <- User.get_or_fetch_by_ap_id(actor), # {:ok, object} <- - # get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id), + # fetch_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id), # {:ok, activity} <- ActivityPub.delete(object, false) do # {:ok, activity} # else @@ -208,13 +211,9 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do # def handle_incoming(_), do: :error - def get_obj_helper(id) do - if object = Object.get_by_ap_id(id), do: {:ok, object}, else: nil - end - def set_reply_to_uri(%{"inReplyTo" => in_reply_to} = object) do with false <- String.starts_with?(in_reply_to, "http"), - {:ok, %{data: replied_to_object}} <- get_obj_helper(in_reply_to) do + {:ok, replied_to_object} <- fetch_obj_helper(in_reply_to) do Map.put(object, "inReplyTo", replied_to_object["external_url"] || in_reply_to) else _e -> object @@ -327,7 +326,8 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do end def add_mention_tags(object) do - recipients = object["to"] ++ (object["cc"] || []) + recipients = + (object["to"] ++ (object["cc"] || [])) -- ["https://www.w3.org/ns/activitystreams#Public"] mentions = recipients @@ -391,6 +391,9 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do # |> Map.put("attachment", attachments) # end + @spec fetch_obj_helper(String.t()) :: {:ok, %Event{}} | {:ok, %Comment{}} | {:error, any()} def fetch_obj_helper(url) when is_bitstring(url), do: ActivityPub.fetch_object_from_url(url) + + @spec fetch_obj_helper(map()) :: {:ok, %Event{}} | {:ok, %Comment{}} | {:error, any()} def fetch_obj_helper(obj) when is_map(obj), do: ActivityPub.fetch_object_from_url(obj["id"]) end diff --git a/lib/service/activity_pub/utils.ex b/lib/service/activity_pub/utils.ex index caf69f17d..cea18d744 100644 --- a/lib/service/activity_pub/utils.ex +++ b/lib/service/activity_pub/utils.ex @@ -77,7 +77,17 @@ defmodule Mobilizon.Service.ActivityPub.Utils do to = to ++ (data["cc"] || []) to - |> Enum.map(fn url -> Actors.get_actor_by_url!(url) end) + |> Enum.map(fn url -> Actors.get_actor_by_url(url) end) + |> Enum.map(fn {status, actor} -> + case status do + :ok -> + actor + + _ -> + nil + end + end) + |> Enum.map(& &1) |> Enum.filter(fn actor -> actor && !is_nil(actor.domain) end) end @@ -110,8 +120,8 @@ defmodule Mobilizon.Service.ActivityPub.Utils do @doc """ Inserts a full object if it is contained in an activity. """ - def insert_full_object(%{"object" => %{"type" => type} = object_data}, _local) - when is_map(object_data) and type == "Event" do + def insert_full_object(%{"object" => %{"type" => type} = object_data}, local) + when is_map(object_data) and type == "Event" and not local do with {:ok, _} <- Events.create_event(object_data) do :ok end @@ -121,7 +131,7 @@ defmodule Mobilizon.Service.ActivityPub.Utils do Inserts a full object if it is contained in an activity. """ def insert_full_object(%{"object" => %{"type" => type} = object_data}, local) - when is_map(object_data) and type == "Note" do + when is_map(object_data) and type == "Note" and not local do with {:ok, %Actor{id: actor_id}} <- Actors.get_or_fetch_by_url(object_data["actor"]) do data = %{ "text" => object_data["content"], @@ -164,12 +174,7 @@ defmodule Mobilizon.Service.ActivityPub.Utils do data end - Logger.info("comment data ready to be inserted") - Logger.info(inspect(data)) - with {:ok, comm} <- Events.create_comment(data) do - Logger.info("comment inserted") - Logger.info(inspect(comm)) :ok else err -> @@ -206,6 +211,49 @@ defmodule Mobilizon.Service.ActivityPub.Utils do # Repo.one(query) # end + def make_event_data( + %Event{title: title, organizer_actor: actor, uuid: uuid}, + to \\ ["https://www.w3.org/ns/activitystreams#Public"] + ) do + %{ + "type" => "Event", + "to" => to, + "title" => title, + "actor" => actor.url, + "uuid" => uuid, + "id" => "#{MobilizonWeb.Endpoint.url()}/events/#{uuid}" + } + end + + @doc """ + Make an AP comment object from an existing `Comment` structure. + """ + def make_comment_data( + %Comment{ + text: text, + actor: actor, + uuid: uuid, + in_reply_to_comment: reply_to, + event: event + }, + to \\ ["https://www.w3.org/ns/activitystreams#Public"] + ) do + object = %{ + "type" => "Note", + "to" => to, + "content" => text, + "actor" => actor.url, + "uuid" => uuid, + "id" => "#{MobilizonWeb.Endpoint.url()}/comments/#{uuid}" + } + + if reply_to do + object |> Map.put("inReplyTo", reply_to.url || event.url) + else + object + end + end + def make_comment_data( actor, to, @@ -344,7 +392,7 @@ defmodule Mobilizon.Service.ActivityPub.Utils do #### Create-related helpers - def make_create_data(params, additional) do + def make_create_data(params, additional \\ %{}) do published = params.published || make_date() %{ diff --git a/lib/service/federator.ex b/lib/service/federator.ex index 27b676d5c..0711a02d3 100644 --- a/lib/service/federator.ex +++ b/lib/service/federator.ex @@ -44,7 +44,7 @@ defmodule Mobilizon.Service.Federator do def handle(:incoming_ap_doc, params) do Logger.info("Handling incoming AP activity") - Logger.info(inspect(params)) + Logger.debug(inspect(params)) with {:ok, _activity} <- Transmogrifier.handle_incoming(params) do else @@ -53,8 +53,8 @@ defmodule Mobilizon.Service.Federator do _e -> # Just drop those for now - Logger.info("Unhandled activity") - Logger.info(Poison.encode!(params, pretty: 2)) + Logger.error("Unhandled activity") + Logger.error(Poison.encode!(params, pretty: 2)) end end diff --git a/lib/service/http_signatures/http_signatures.ex b/lib/service/http_signatures/http_signatures.ex index e5e0d927b..9673a2810 100644 --- a/lib/service/http_signatures/http_signatures.ex +++ b/lib/service/http_signatures/http_signatures.ex @@ -41,20 +41,10 @@ defmodule Mobilizon.Service.HTTPSignatures do :public_key.verify(sigstring, :sha256, sig, public_key) end - defp prepare_public_key(public_key_code) do - with [public_key_entry] <- :public_key.pem_decode(public_key_code) do - {:ok, :public_key.pem_entry_decode(public_key_entry)} - else - _err -> - {:error, :pem_decode_error} - end - end - def validate_conn(conn) do # TODO: How to get the right key and see if it is actually valid for that request. # For now, fetch the key for the actor. - with {:ok, public_key} <- conn.params["actor"] |> Actor.get_public_key_for_url(), - {:ok, public_key} <- prepare_public_key(public_key) do + with {:ok, public_key} <- conn.params["actor"] |> Actor.get_public_key_for_url() do if validate_conn(conn, public_key) do true else @@ -62,8 +52,7 @@ defmodule Mobilizon.Service.HTTPSignatures do # Fetch user anew and try one more time with actor_id <- conn.params["actor"], {:ok, _actor} <- ActivityPub.make_actor_from_url(actor_id), - {:ok, public_key} <- actor_id |> Actor.get_public_key_for_url(), - {:ok, public_key} <- prepare_public_key(public_key) do + {:ok, public_key} <- actor_id |> Actor.get_public_key_for_url() do validate_conn(conn, public_key) end end @@ -91,7 +80,7 @@ defmodule Mobilizon.Service.HTTPSignatures do def sign(%Actor{} = actor, headers) do with sigstring <- build_signing_string(headers, Map.keys(headers)), - {:ok, key} <- actor.keys |> prepare_public_key(), + {:ok, key} <- actor.keys |> Actor.prepare_public_key(), signature <- sigstring |> :public_key.sign(:sha256, key) |> Base.encode64() do [ keyId: actor.url <> "#main-key", diff --git a/mix.exs b/mix.exs index f16a3806a..396d952dc 100644 --- a/mix.exs +++ b/mix.exs @@ -90,7 +90,8 @@ defmodule Mobilizon.Mixfile do {:excoveralls, "~> 0.8", only: :test}, {:ex_doc, "~> 0.16", only: :dev, runtime: false}, {:mix_test_watch, "~> 0.5", only: :dev, runtime: false}, - {:ex_unit_notifier, "~> 0.1", only: :test} + {:ex_unit_notifier, "~> 0.1", only: :test}, + {:dialyxir, "~> 1.0.0-rc.4", only: [:dev], runtime: false} ] end diff --git a/mix.lock b/mix.lock index 35b88b924..c4544b8eb 100644 --- a/mix.lock +++ b/mix.lock @@ -2,7 +2,7 @@ "absinthe": {:hex, :absinthe, "1.4.13", "81eb2ff41f1b62cd6e992955f62c22c042d1079b7936c27f5f7c2c806b8fc436", [:mix], [{:dataloader, "~> 1.0.0", [hex: :dataloader, repo: "hexpm", optional: true]}, {:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"}, "absinthe_ecto": {:hex, :absinthe_ecto, "0.1.3", "420b68129e79fe4571a4838904ba03e282330d335da47729ad52ffd7b8c5fcb1", [:mix], [{:absinthe, "~> 1.3.0 or ~> 1.4.0", [hex: :absinthe, repo: "hexpm", optional: false]}, {:ecto, ">= 0.0.0", [hex: :ecto, repo: "hexpm", optional: false]}], "hexpm"}, "absinthe_phoenix": {:hex, :absinthe_phoenix, "1.4.3", "cea34e7ebbc9a252038c1f1164878ee86bcb108905fe462be77efacda15c1e70", [:mix], [{:absinthe, "~> 1.4.0", [hex: :absinthe, repo: "hexpm", optional: false]}, {:absinthe_plug, "~> 1.4.0", [hex: :absinthe_plug, repo: "hexpm", optional: false]}, {:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.2", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.10.5 or ~> 2.11", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:poison, "~> 2.0 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"}, - "absinthe_plug": {:hex, :absinthe_plug, "1.4.5", "f63d52a76c870cd5f11d4bed8f61351ab5c5f572c5eb0479a0137f9f730ba33d", [:mix], [{:absinthe, "~> 1.4.11", [hex: :absinthe, repo: "hexpm", optional: false]}, {:plug, "~> 1.3.2 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, + "absinthe_plug": {:hex, :absinthe_plug, "1.4.6", "ac5d2d3d02acf52fda0f151b294017ab06e2ed1c6c15334e06aac82c94e36e08", [:mix], [{:absinthe, "~> 1.4.11", [hex: :absinthe, repo: "hexpm", optional: false]}, {:plug, "~> 1.3.2 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "arc": {:hex, :arc, "0.11.0", "ac7a0cc03035317b6fef9fe94c97d7d9bd183a3e7ce1606aa0c175cfa8d1ba6d", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:ex_aws_s3, "~> 2.0", [hex: :ex_aws_s3, repo: "hexpm", optional: true]}, {:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:poison, "~> 2.2 or ~> 3.1", [hex: :poison, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm"}, "arc_ecto": {:hex, :arc_ecto, "0.11.0", "41f19944df3804b49c7bf511dfbeffe09b5b500892ed70d062d891bc891de589", [:mix], [{:arc, "~> 0.11.0", [hex: :arc, repo: "hexpm", optional: false]}, {:ecto, "~> 2.1", [hex: :ecto, repo: "hexpm", optional: false]}], "hexpm"}, "argon2_elixir": {:hex, :argon2_elixir, "1.3.1", "02a3d55a2670d25df25d75adcef2d74662c72bbc85aba17ca0ea585764b59ef4", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm"}, @@ -21,16 +21,18 @@ "dataloader": {:hex, :dataloader, "1.0.4", "7c2345c53c9e5b61420013fc53c8463ba347a938b61f66677eb47d9c4a53ac5d", [:mix], [{:ecto, ">= 0.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"}, "db_connection": {:hex, :db_connection, "1.1.3", "89b30ca1ef0a3b469b1c779579590688561d586694a3ce8792985d4d7e575a61", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"}, "decimal": {:hex, :decimal, "1.5.0", "b0433a36d0e2430e3d50291b1c65f53c37d56f83665b43d79963684865beab68", [:mix], [], "hexpm"}, + "dialyxir": {:hex, :dialyxir, "1.0.0-rc.4", "71b42f5ee1b7628f3e3a6565f4617dfb02d127a0499ab3e72750455e986df001", [:mix], [{:erlex, "~> 0.1", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm"}, "earmark": {:hex, :earmark, "1.2.6", "b6da42b3831458d3ecc57314dff3051b080b9b2be88c2e5aa41cd642a5b044ed", [:mix], [], "hexpm"}, "ecto": {:hex, :ecto, "2.2.11", "4bb8f11718b72ba97a2696f65d247a379e739a0ecabf6a13ad1face79844791c", [:mix], [{:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: true]}, {:decimal, "~> 1.2", [hex: :decimal, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.8.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"}, "ecto_autoslug_field": {:hex, :ecto_autoslug_field, "0.5.1", "c8a160fa6e5e0002740fe1c500bcc27d10bdb073a93715ce8a01b7af8a290777", [:mix], [{:ecto, ">= 2.1.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:slugger, ">= 0.2.0", [hex: :slugger, repo: "hexpm", optional: false]}], "hexpm"}, "ecto_enum": {:hex, :ecto_enum, "1.1.0", "d44fe2ce6e1c0e907e7c3b6456a69e0f1d662348d8b4e2a662ba312223d8ff62", [:mix], [{:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm"}, "elixir_make": {:hex, :elixir_make, "0.4.2", "332c649d08c18bc1ecc73b1befc68c647136de4f340b548844efc796405743bf", [:mix], [], "hexpm"}, "email_checker": {:hex, :email_checker, "0.1.2", "05b3121c71b69f1ab5df7d8b4844046898bf218031998ef53f20c6b8bfd219e9", [:mix], [{:socket, "~> 0.3.1", [hex: :socket, repo: "hexpm", optional: false]}], "hexpm"}, + "erlex": {:hex, :erlex, "0.1.6", "c01c889363168d3fdd23f4211647d8a34c0f9a21ec726762312e08e083f3d47e", [:mix], [], "hexpm"}, "ex_crypto": {:hex, :ex_crypto, "0.9.0", "e04a831034c4d0a43fb2858f696d6b5ae0f87f07dedca3452912fd3cb5ee3ca2", [:mix], [{:poison, ">= 2.0.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"}, "ex_doc": {:hex, :ex_doc, "0.19.1", "519bb9c19526ca51d326c060cb1778d4a9056b190086a8c6c115828eaccea6cf", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.7", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"}, "ex_ical": {:hex, :ex_ical, "0.2.0", "4b928b554614704016cc0c9ee226eb854da9327a1cc460457621ceacb1ac29a6", [:mix], [{:timex, "~> 3.1", [hex: :timex, repo: "hexpm", optional: false]}], "hexpm"}, - "ex_machina": {:hex, :ex_machina, "2.2.0", "fec496331e04fc2db2a1a24fe317c12c0c4a50d2beb8ebb3531ed1f0d84be0ed", [:mix], [{:ecto, "~> 2.1", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"}, + "ex_machina": {:hex, :ex_machina, "2.2.2", "d84217a6fb7840ff771d2561b8aa6d74a0d8968e4b10ecc0d7e9890dc8fb1c6a", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm"}, "ex_unit_notifier": {:hex, :ex_unit_notifier, "0.1.4", "36a2dcab829f506e01bf17816590680dd1474407926d43e64c1263e627c364b8", [:mix], [], "hexpm"}, "excoveralls": {:hex, :excoveralls, "0.9.2", "299ea4903be7cb2959af0f919d258af116736ca8d507f86c12ef2184698e21a0", [:mix], [{:hackney, ">= 0.12.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"}, "exgravatar": {:hex, :exgravatar, "2.0.1", "66d595c7d63dd6bbac442c5542a724375ae29144059c6fe093e61553850aace4", [:mix], [], "hexpm"}, @@ -45,10 +47,10 @@ "guardian_db": {:hex, :guardian_db, "1.1.0", "45ab94206cce38f7443dc27de6dc52966ccbdeff65ca1b1f11a6d8f3daceb556", [:mix], [{:ecto, "~> 2.2", [hex: :ecto, repo: "hexpm", optional: false]}, {:guardian, "~> 1.0", [hex: :guardian, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm"}, "hackney": {:hex, :hackney, "1.12.1", "8bf2d0e11e722e533903fe126e14d6e7e94d9b7983ced595b75f532e04b7fdc7", [:rebar3], [{:certifi, "2.3.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "5.1.1", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"}, "http_sign": {:hex, :http_sign, "0.1.1", "b16edb83aa282892f3271f9a048c155e772bf36e15700ab93901484c55f8dd10", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, - "httpoison": {:hex, :httpoison, "1.3.1", "7ac607311f5f706b44e8b3fab736d0737f2f62a31910ccd9afe7227b43edb7f0", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, + "httpoison": {:hex, :httpoison, "1.4.0", "e0b3c2ad6fa573134e42194d13e925acfa8f89d138bc621ffb7b1989e6d22e73", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, "icalendar": {:hex, :icalendar, "0.7.0", "6acf28c7e38ad1c4515c59e336878fb78bb646c8aa70d2ee3786ea194711a7b7", [:mix], [{:timex, "~> 3.0", [hex: :timex, repo: "hexpm", optional: false]}], "hexpm"}, "idna": {:hex, :idna, "5.1.1", "cbc3b2fa1645113267cc59c760bafa64b2ea0334635ef06dbac8801e42f7279c", [:rebar3], [{:unicode_util_compat, "0.3.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"}, - "jason": {:hex, :jason, "1.1.1", "d3ccb840dfb06f2f90a6d335b536dd074db748b3e7f5b11ab61d239506585eb2", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"}, + "jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"}, "jose": {:hex, :jose, "1.8.4", "7946d1e5c03a76ac9ef42a6e6a20001d35987afd68c2107bcd8f01a84e75aa73", [:mix, :rebar3], [{:base64url, "~> 0.0.1", [hex: :base64url, repo: "hexpm", optional: false]}], "hexpm"}, "json_ld": {:hex, :json_ld, "0.3.0", "92f508ca831b9e4530e3e6c950976fdafcf26323e6817c325b3e1ee78affc4bd", [:mix], [{:jason, "~> 1.1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:rdf, "~> 0.5", [hex: :rdf, repo: "hexpm", optional: false]}], "hexpm"}, "jsx": {:hex, :jsx, "2.8.3", "a05252d381885240744d955fbe3cf810504eb2567164824e19303ea59eef62cf", [:mix, :rebar3], [], "hexpm"}, @@ -64,21 +66,22 @@ "nimble_parsec": {:hex, :nimble_parsec, "0.4.0", "ee261bb53214943679422be70f1658fff573c5d0b0a1ecd0f18738944f818efe", [:mix], [], "hexpm"}, "parse_trans": {:hex, :parse_trans, "3.2.0", "2adfa4daf80c14dc36f522cf190eb5c4ee3e28008fc6394397c16f62a26258c2", [:rebar3], [], "hexpm"}, "phoenix": {:hex, :phoenix, "1.3.4", "aaa1b55e5523083a877bcbe9886d9ee180bf2c8754905323493c2ac325903dc5", [:mix], [{:cowboy, "~> 1.0", [hex: :cowboy, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.3.3 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"}, - "phoenix_ecto": {:hex, :phoenix_ecto, "3.4.0", "91cd39427006fe4b5588d69f0941b9c3d3d8f5e6477c563a08379de7de2b0c58", [:mix], [{:ecto, "~> 2.1", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, + "phoenix_ecto": {:hex, :phoenix_ecto, "3.6.0", "d65dbcedd6af568d8582dcd7da516c3051016bad51f9953e5337fea40bcd8a9d", [:mix], [{:ecto, "~> 2.2", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix_html": {:hex, :phoenix_html, "2.12.0", "1fb3c2e48b4b66d75564d8d63df6d53655469216d6b553e7e14ced2b46f97622", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, - "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.1.6", "7280f4dd88d38ee07ca70a2974ca12b9bfdbb9fa8137e4692889cf097c1bb232", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.0 or ~> 1.2 or ~> 1.3", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm"}, - "phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.0", "d55e25ff1ff8ea2f9964638366dfd6e361c52dedfd50019353598d11d4441d14", [:mix], [], "hexpm"}, - "plug": {:hex, :plug, "1.6.4", "35618dd2cc009b69b000f785452f6b370f76d099ece199733fea27bc473f809d", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}], "hexpm"}, + "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.1.7", "425fff579085f7eacaf009e71940be07338c8d8b78d16e307c50c7d82a381497", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.0 or ~> 1.2 or ~> 1.3 or ~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm"}, + "phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.1", "6668d787e602981f24f17a5fbb69cc98f8ab085114ebfac6cc36e10a90c8e93c", [:mix], [], "hexpm"}, + "plug": {:hex, :plug, "1.7.1", "8516d565fb84a6a8b2ca722e74e2cd25ca0fc9d64f364ec9dbec09d33eb78ccd", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}], "hexpm"}, + "plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"}, "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"}, "poolboy": {:hex, :poolboy, "1.5.1", "6b46163901cfd0a1b43d692657ed9d7e599853b3b21b95ae5ae0a777cf9b6ca8", [:rebar], [], "hexpm"}, "postgrex": {:hex, :postgrex, "0.13.5", "3d931aba29363e1443da167a4b12f06dcd171103c424de15e5f3fc2ba3e6d9c5", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm"}, "ranch": {:hex, :ranch, "1.3.2", "e4965a144dc9fbe70e5c077c65e73c57165416a901bd02ea899cfd95aa890986", [:rebar3], [], "hexpm"}, - "rdf": {:hex, :rdf, "0.5.1", "b59eaf5df3d77c6c3bb35efdb61f30ba8a1321c03206449ea71fb58670e94f1d", [:mix], [{:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm"}, + "rdf": {:hex, :rdf, "0.5.3", "2990ce6ca55602db9c170e6258bf3fa39b0e4be3d49b1c09c00a740bc387029f", [:mix], [{:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm"}, "rsa_ex": {:hex, :rsa_ex, "0.4.0", "e28dd7dc5236e156df434af0e4aa822384c8866c928e17b785d4edb7c253b558", [:mix], [], "hexpm"}, "slugger": {:hex, :slugger, "0.3.0", "efc667ab99eee19a48913ccf3d038b1fb9f165fa4fbf093be898b8099e61b6ed", [:mix], [], "hexpm"}, "socket": {:hex, :socket, "0.3.13", "98a2ab20ce17f95fb512c5cadddba32b57273e0d2dba2d2e5f976c5969d0c632", [:mix], [], "hexpm"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [:make, :rebar], [], "hexpm"}, - "timex": {:hex, :timex, "3.4.1", "e63fc1a37453035e534c3febfe9b6b9e18583ec7b37fd9c390efdef97397d70b", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"}, + "timex": {:hex, :timex, "3.4.2", "d74649c93ad0e12ce5b17cf5e11fbd1fb1b24a3d114643e86dba194b64439547", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"}, "timex_ecto": {:hex, :timex_ecto, "3.3.0", "d5bdef09928e7a60f10a0baa47ce653f29b43d6fee87b30b236b216d0e36b98d", [:mix], [{:ecto, "~> 2.2", [hex: :ecto, repo: "hexpm", optional: false]}, {:timex, "~> 3.1", [hex: :timex, repo: "hexpm", optional: false]}], "hexpm"}, "tzdata": {:hex, :tzdata, "0.5.19", "7962a3997bf06303b7d1772988ede22260f3dae1bf897408ebdac2b4435f4e6a", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.3.1", "a1f612a7b512638634a603c8f401892afbf99b8ce93a45041f8aaca99cadb85e", [:rebar3], [], "hexpm"}, diff --git a/test/mobilizon/actors/actors_test.exs b/test/mobilizon/actors/actors_test.exs index b4a523694..1a3e6fc5b 100644 --- a/test/mobilizon/actors/actors_test.exs +++ b/test/mobilizon/actors/actors_test.exs @@ -1,12 +1,11 @@ defmodule Mobilizon.ActorsTest do use Mobilizon.DataCase - import Mobilizon.Factory alias Mobilizon.Actors + alias Mobilizon.Actors.{Actor, Member, Follower, User, Bot} + import Mobilizon.Factory describe "actors" do - alias Mobilizon.Actors.Actor - @valid_attrs %{ summary: "some description", name: "Bobby Blank", @@ -49,24 +48,24 @@ defmodule Mobilizon.ActorsTest do {:ok, actor: actor} end - test "list_actors/0 returns all actors", %{actor: actor} do - actors = Actors.list_actors() - assert actors = [actor] + test "list_actors/0 returns all actors", %{actor: %Actor{id: actor_id}} do + assert actor_id == hd(Actors.list_actors()).id end - test "get_actor!/1 returns the actor with given id", %{actor: actor} do - actor_fetched = Actors.get_actor!(actor.id) - assert actor_fetched = actor + test "get_actor!/1 returns the actor with given id", %{actor: %Actor{id: actor_id} = actor} do + assert actor_id == Actors.get_actor!(actor.id).id end - test "get_actor_for_user/1 returns the actor for an user", %{actor: %{user: user} = actor} do - assert actor = Actors.get_actor_for_user(user) + test "get_actor_for_user/1 returns the actor for an user", %{ + actor: %{user: user, id: actor_id} = _actor + } do + assert actor_id == Actors.get_actor_for_user(user).id end test "get_actor_for_user/1 returns the actor for an user with no default actor defined" do user = insert(:user) - actor = insert(:actor, user: user) - assert actor = Actors.get_actor_for_user(user) + actor_id = insert(:actor, user: user).id + assert actor_id == Actors.get_actor_for_user(user).id end test "get_actor_with_everything!/1 returns the actor with it's organized events", %{ @@ -74,19 +73,28 @@ defmodule Mobilizon.ActorsTest do } do assert Actors.get_actor_with_everything!(actor.id).organized_events == [] event = insert(:event, organizer_actor: actor) - events = Actors.get_actor_with_everything!(actor.id).organized_events - assert events = [event] + + event_found_id = + Actors.get_actor_with_everything!(actor.id).organized_events |> hd |> Map.get(:id) + + assert event_found_id == event.id end - test "get_actor_by_name/1 returns a local actor", %{actor: actor} do - actor_found = Actors.get_actor_by_name(actor.preferred_username) - assert actor_found = actor + test "get_actor_by_name/1 returns a local actor", %{ + actor: %Actor{id: actor_id, preferred_username: preferred_username} + } do + actor_found_id = Actors.get_actor_by_name(preferred_username).id + assert actor_found_id == actor_id end test "get_actor_by_name/1 returns a remote actor" do - assert {:ok, %Actor{} = actor} = Actors.get_or_fetch_by_url(@remote_account_url) - actor_found = Actors.get_actor_by_name("#{actor.preferred_username}@#{actor.domain}") - assert actor_found = actor + with {:ok, + %Actor{id: actor_id, preferred_username: preferred_username, domain: domain} = _actor} <- + Actors.get_or_fetch_by_url(@remote_account_url), + %Actor{id: actor_found_id} <- + Actors.get_actor_by_name("#{preferred_username}@#{domain}").id do + assert actor_found_id == actor_id + end end test "get_local_actor_by_name_with_everything!/1 returns the local actor with it's organized events", @@ -98,10 +106,12 @@ defmodule Mobilizon.ActorsTest do event = insert(:event, organizer_actor: actor) - events = + event_found_id = Actors.get_local_actor_by_name_with_everything(actor.preferred_username).organized_events + |> hd + |> Map.get(:id) - assert events = [event] + assert event_found_id == event.id end test "get_actor_by_name_with_everything!/1 returns the local actor with it's organized events", @@ -112,8 +122,13 @@ defmodule Mobilizon.ActorsTest do [] event = insert(:event, organizer_actor: actor) - events = Actors.get_actor_by_name_with_everything(actor.preferred_username).organized_events - assert events = [event] + + event_found_id = + Actors.get_actor_by_name_with_everything(actor.preferred_username).organized_events + |> hd + |> Map.get(:id) + + assert event_found_id == event.id end test "get_actor_by_name_with_everything!/1 returns the remote actor with it's organized events" do @@ -125,75 +140,83 @@ defmodule Mobilizon.ActorsTest do event = insert(:event, organizer_actor: actor) - events = + event_found_id = Actors.get_actor_by_name_with_everything("#{actor.preferred_username}@#{actor.domain}").organized_events + |> hd + |> Map.get(:id) - assert events = [event] + assert event_found_id == event.id end test "get_or_fetch_by_url/1 returns the local actor for the url", %{ - actor: actor + actor: %Actor{preferred_username: preferred_username} = actor } do - preferred_username = actor.preferred_username - - assert {:ok, %Actor{preferred_username: preferred_username, domain: nil} = actor_found} = - Actors.get_or_fetch_by_url(actor.url) + with {:ok, %Actor{domain: domain} = actor} <- Actors.get_or_fetch_by_url(actor.url) do + assert preferred_username == actor.preferred_username + assert is_nil(domain) + end end test "get_or_fetch_by_url/1 returns the remote actor for the url" do - assert {:ok, - %Actor{preferred_username: @remote_account_username, domain: @remote_account_domain}} = - Actors.get_or_fetch_by_url(@remote_account_url) + with {:ok, %Actor{preferred_username: preferred_username, domain: domain}} <- + Actors.get_or_fetch_by_url!(@remote_account_url) do + assert preferred_username == @remote_account_username + assert domain == @remote_account_domain + end end test "test find_local_by_username/1 returns local actors with similar usernames", %{ actor: actor } do actor2 = insert(:actor) - actors = Actors.find_local_by_username("thomas") - assert actors = [actor, actor2] + [%Actor{id: actor_found_id} | tail] = Actors.find_local_by_username("thomas") + %Actor{id: actor2_found_id} = hd(tail) + assert actor_found_id == actor.id + assert actor2_found_id == actor2.id end test "test find_actors_by_username_or_name/1 returns actors with similar usernames", %{ - actor: actor + actor: %Actor{id: actor_id} } do - {:ok, %Actor{} = actor2} = Actors.get_or_fetch_by_url(@remote_account_url) - actors = Actors.find_actors_by_username_or_name("t") - assert actors = [actor, actor2] + {:ok, %Actor{id: actor2_id}} = Actors.get_or_fetch_by_url(@remote_account_url) + actors_ids = Actors.find_actors_by_username_or_name("t") |> Enum.map(& &1.id) + assert MapSet.new(actors_ids) == MapSet.new([actor2_id, actor_id]) end - test "test find_actors_by_username_or_name/1 returns actors with similar names", %{ - actor: actor - } do + test "test find_actors_by_username_or_name/1 returns actors with similar names" do actors = Actors.find_actors_by_username_or_name("ohno") assert actors == [] end test "test search/1 returns accounts for search with existing accounts", %{actor: actor} do - assert {:ok, [actor]} = Actors.search("t") + with {:ok, [%Actor{id: actor_found_id}]} <- Actors.search("t") do + assert actor_found_id == actor.id + end end test "test search/1 returns accounts for search with non existent accounts" do - assert {:ok, []} = Actors.search("nonexistent") + assert {:ok, []} == Actors.search("nonexistent") end test "test search/1 returns accounts for search with existing remote accounts" do - assert {:ok, [%Actor{preferred_username: "tcit", domain: "framapiaf.org"}]} = - Actors.search("tcit@framapiaf.org") + with {:ok, [%Actor{preferred_username: username}]} <- Actors.search("tcit@framapiaf.org") do + assert username == "tcit" + end end test "test search/1 returns accounts for search with non existent remote accounts" do - assert {:error, _} = Actors.search("tcit@yolo.tld") + assert {:error, "No ActivityPub URL found in WebFinger"} == Actors.search("tcit@yolo.tld") end test "test get_public_key_for_url/1 with local actor", %{actor: actor} do assert Actor.get_public_key_for_url(actor.url) == - actor.keys |> Mobilizon.Service.ActivityPub.Utils.pem_to_public_key() + actor.keys |> Mobilizon.Actors.Actor.prepare_public_key() end - @remote_actor_key {:RSAPublicKey, - 20_890_513_599_005_517_665_557_846_902_571_022_168_782_075_040_010_449_365_706_450_877_170_130_373_892_202_874_869_873_999_284_399_697_282_332_064_948_148_602_583_340_776_692_090_472_558_740_998_357_203_838_580_321_412_679_020_304_645_826_371_196_718_081_108_049_114_160_630_664_514_340_729_769_453_281_682_773_898_619_827_376_232_969_899_348_462_205_389_310_883_299_183_817_817_999_273_916_446_620_095_414_233_374_619_948_098_516_821_650_069_821_783_810_210_582_035_456_563_335_930_330_252_551_528_035_801_173_640_288_329_718_719_895_926_309_416_142_129_926_226_047_930_429_802_084_560_488_897_717_417_403_272_782_469_039_131_379_953_278_833_320_195_233_761_955_815_307_522_871_787_339_192_744_439_894_317_730_207_141_881_699_363_391_788_150_650_217_284_777_541_358_381_165_360_697_136_307_663_640_904_621_178_632_289_787, - 65537} + @remote_actor_key {:ok, + {:RSAPublicKey, + 20_890_513_599_005_517_665_557_846_902_571_022_168_782_075_040_010_449_365_706_450_877_170_130_373_892_202_874_869_873_999_284_399_697_282_332_064_948_148_602_583_340_776_692_090_472_558_740_998_357_203_838_580_321_412_679_020_304_645_826_371_196_718_081_108_049_114_160_630_664_514_340_729_769_453_281_682_773_898_619_827_376_232_969_899_348_462_205_389_310_883_299_183_817_817_999_273_916_446_620_095_414_233_374_619_948_098_516_821_650_069_821_783_810_210_582_035_456_563_335_930_330_252_551_528_035_801_173_640_288_329_718_719_895_926_309_416_142_129_926_226_047_930_429_802_084_560_488_897_717_417_403_272_782_469_039_131_379_953_278_833_320_195_233_761_955_815_307_522_871_787_339_192_744_439_894_317_730_207_141_881_699_363_391_788_150_650_217_284_777_541_358_381_165_360_697_136_307_663_640_904_621_178_632_289_787, + 65537}} test "test get_public_key_for_url/1 with remote actor" do assert Actor.get_public_key_for_url(@remote_account_url) == @remote_actor_key end @@ -260,18 +283,14 @@ defmodule Mobilizon.ActorsTest do @update_attrs %{email: "foo@fighters.tld", password: "some updated password", role: 43} @invalid_attrs %{email: nil, password_hash: nil, role: nil} - def user_fixture(attrs \\ %{}) do - insert(:user) - end - test "list_users/0 returns all users" do - user = user_fixture() + user = insert(:user) users = Actors.list_users() - assert users = [user] + assert users == [user] end test "get_user!/1 returns the user with given id" do - user = user_fixture() + user = insert(:user) assert user = Actors.get_user!(user.id) end @@ -288,7 +307,7 @@ defmodule Mobilizon.ActorsTest do end test "update_user/2 with valid data updates the user" do - user = user_fixture() + user = insert(:user) assert {:ok, user} = Actors.update_user(user, @update_attrs) assert %User{} = user assert user.email == "foo@fighters.tld" @@ -296,19 +315,19 @@ defmodule Mobilizon.ActorsTest do end test "update_user/2 with invalid data returns error changeset" do - user = user_fixture() + user = insert(:user) assert {:error, %Ecto.Changeset{}} = Actors.update_user(user, @invalid_attrs) assert user = Actors.get_user!(user.id) end test "delete_user/1 deletes the user" do - user = user_fixture() + user = insert(:user) assert {:ok, %User{}} = Actors.delete_user(user) assert_raise Ecto.NoResultsError, fn -> Actors.get_user!(user.id) end end test "change_user/1 returns a user changeset" do - user = user_fixture() + user = insert(:user) assert %Ecto.Changeset{} = Actors.change_user(user) end @@ -335,7 +354,7 @@ defmodule Mobilizon.ActorsTest do end test "get_user_by_email/1 finds an activated user by it's email" do - {:ok, %Actor{user: %User{email: email} = user} = _actor} = + {:ok, %Actor{user: user}} = Actors.register(%{email: @email, password: @password, username: "yolo"}) {:ok, %User{id: id}} = Actors.get_user_by_email(@email, false) @@ -393,19 +412,15 @@ defmodule Mobilizon.ActorsTest do @update_attrs %{source: "some updated source", type: "some updated type"} @invalid_attrs %{source: nil, type: nil} - def bot_fixture(attrs \\ %{}) do - insert(:bot) - end - test "list_bots/0 returns all bots" do - bot = bot_fixture() - bots = Actors.list_bots() - assert bots = [bot] + bot = insert(:bot) + bot_found_id = Actors.list_bots() |> hd |> Map.get(:id) + assert bot_found_id == bot.id end test "get_bot!/1 returns the bot with given id" do - bot = bot_fixture() - assert bot = Actors.get_bot!(bot.id) + %Bot{id: bot_id} = bot = insert(:bot) + assert bot_id == Actors.get_bot!(bot.id).id end test "create_bot/1 with valid data creates a bot" do @@ -420,31 +435,36 @@ defmodule Mobilizon.ActorsTest do end test "create_bot/1 with invalid data returns error changeset" do - assert {:error, %Ecto.Changeset{}} = Actors.create_bot(@invalid_attrs) + with {:error, %Ecto.Changeset{}} <- Actors.create_bot(@invalid_attrs) do + assert true + else + _ -> + assert false + end end test "update_bot/2 with valid data updates the bot" do - bot = bot_fixture() - assert {:ok, bot} = Actors.update_bot(bot, @update_attrs) - assert %Bot{} = bot - assert bot.source == "some updated source" - assert bot.type == "some updated type" + with bot <- insert(:bot), + {:ok, %Bot{source: source, type: type}} <- Actors.update_bot(bot, @update_attrs) do + assert source == "some updated source" + assert type == "some updated type" + end end test "update_bot/2 with invalid data returns error changeset" do - bot = bot_fixture() + bot = insert(:bot) assert {:error, %Ecto.Changeset{}} = Actors.update_bot(bot, @invalid_attrs) assert bot = Actors.get_bot!(bot.id) end test "delete_bot/1 deletes the bot" do - bot = bot_fixture() + bot = insert(:bot) assert {:ok, %Bot{}} = Actors.delete_bot(bot) assert_raise Ecto.NoResultsError, fn -> Actors.get_bot!(bot.id) end end test "change_bot/1 returns a bot changeset" do - bot = bot_fixture() + bot = insert(:bot) assert %Ecto.Changeset{} = Actors.change_bot(bot) end end @@ -463,12 +483,12 @@ defmodule Mobilizon.ActorsTest do {:ok, actor: actor, target_actor: target_actor} end - defp create_follower(%{actor: actor, target_actor: target_actor}) do + defp create_test_follower(%{actor: actor, target_actor: target_actor}) do insert(:follower, actor: actor, target_actor: target_actor) end test "get_follower!/1 returns the follower with given id", context do - follower = create_follower(context) + follower = create_test_follower(context) assert follower = Actors.get_follower!(follower.id) end @@ -493,7 +513,7 @@ defmodule Mobilizon.ActorsTest do actor: actor, target_actor: target_actor } do - create_follower(%{actor: actor, target_actor: target_actor}) + create_test_follower(%{actor: actor, target_actor: target_actor}) valid_attrs = @valid_attrs @@ -516,7 +536,7 @@ defmodule Mobilizon.ActorsTest do end test "update_follower/2 with valid data updates the follower", context do - follower = create_follower(context) + follower = create_test_follower(context) assert {:ok, follower} = Actors.update_follower(follower, @update_attrs) assert %Follower{} = follower assert follower.approved == false @@ -524,19 +544,19 @@ defmodule Mobilizon.ActorsTest do end test "update_follower/2 with invalid data returns error changeset", context do - follower = create_follower(context) + follower = create_test_follower(context) assert {:error, %Ecto.Changeset{}} = Actors.update_follower(follower, @invalid_attrs) assert follower = Actors.get_follower!(follower.id) end test "delete_follower/1 deletes the follower", context do - follower = create_follower(context) + follower = create_test_follower(context) assert {:ok, %Follower{}} = Actors.delete_follower(follower) assert_raise Ecto.NoResultsError, fn -> Actors.get_follower!(follower.id) end end test "change_follower/1 returns a follower changeset", context do - follower = create_follower(context) + follower = create_test_follower(context) assert %Ecto.Changeset{} = Actors.change_follower(follower) end end @@ -555,12 +575,12 @@ defmodule Mobilizon.ActorsTest do {:ok, actor: actor, group: group} end - defp create_member(%{actor: actor, group: group}) do + defp create_test_member(%{actor: actor, group: group}) do insert(:member, actor: actor, parent: group) end test "get_member!/1 returns the member with given id", context do - member = create_member(context) + member = create_test_member(context) assert member = Actors.get_member!(member.id) end @@ -585,7 +605,7 @@ defmodule Mobilizon.ActorsTest do actor: actor, group: group } do - create_member(%{actor: actor, group: group}) + create_test_member(%{actor: actor, group: group}) valid_attrs = @valid_attrs @@ -595,10 +615,7 @@ defmodule Mobilizon.ActorsTest do assert {:error, _member} = Actors.create_member(valid_attrs) end - test "create_member/1 with invalid data returns error changeset", %{ - actor: actor, - group: group - } do + test "create_member/1 with invalid data returns error changeset" do invalid_attrs = @invalid_attrs |> Map.put(:actor_id, nil) @@ -608,7 +625,7 @@ defmodule Mobilizon.ActorsTest do end test "update_member/2 with valid data updates the member", context do - member = create_member(context) + member = create_test_member(context) assert {:ok, member} = Actors.update_member(member, @update_attrs) assert %Member{} = member assert member.approved == false @@ -623,13 +640,13 @@ defmodule Mobilizon.ActorsTest do # end test "delete_member/1 deletes the member", context do - member = create_member(context) + member = create_test_member(context) assert {:ok, %Member{}} = Actors.delete_member(member) assert_raise Ecto.NoResultsError, fn -> Actors.get_member!(member.id) end end test "change_member/1 returns a member changeset", context do - member = create_member(context) + member = create_test_member(context) assert %Ecto.Changeset{} = Actors.change_member(member) end end diff --git a/test/mobilizon/addresses/addresses_test.exs b/test/mobilizon/addresses/addresses_test.exs index 6ffa2943a..fcb20420f 100644 --- a/test/mobilizon/addresses/addresses_test.exs +++ b/test/mobilizon/addresses/addresses_test.exs @@ -26,16 +26,16 @@ defmodule Mobilizon.AddressesTest do streetAddress: "some updated streetAddress", geom: %Geo.Point{coordinates: {20, -20}, srid: 4326} } - @invalid_attrs %{ - addressCountry: nil, - addressLocality: nil, - addressRegion: nil, - description: nil, - floor: nil, - postalCode: nil, - streetAddress: nil, - geom: nil - } + # @invalid_attrs %{ + # addressCountry: nil, + # addressLocality: nil, + # addressRegion: nil, + # description: nil, + # floor: nil, + # postalCode: nil, + # streetAddress: nil, + # geom: nil + # } def address_fixture(attrs \\ %{}) do {:ok, address} = diff --git a/test/mobilizon/events/events_test.exs b/test/mobilizon/events/events_test.exs index 46ebc8032..d0a3ea078 100644 --- a/test/mobilizon/events/events_test.exs +++ b/test/mobilizon/events/events_test.exs @@ -4,7 +4,6 @@ defmodule Mobilizon.EventsTest do import Mobilizon.Factory alias Mobilizon.Events - alias Mobilizon.Actors @event_valid_attrs %{ begins_on: "2010-04-17 14:00:00.000000Z", @@ -13,22 +12,6 @@ defmodule Mobilizon.EventsTest do title: "some title" } - def actor_fixture do - insert(:actor) - end - - def address_fixture do - insert(:address) - end - - def event_fixture do - insert(:event) - end - - def category_fixture do - insert(:category) - end - describe "events" do alias Mobilizon.Events.Event @@ -78,14 +61,14 @@ defmodule Mobilizon.EventsTest do assert event2.title == hd(Events.find_events_by_name(" Special ")).title - assert title = hd(Events.find_events_by_name("")).title - assert title2 = hd(tl(Events.find_events_by_name(""))).title + assert title == hd(Events.find_events_by_name("")).title + assert title2 == hd(tl(Events.find_events_by_name(""))).title end test "create_event/1 with valid data creates a event" do - actor = actor_fixture() - category = category_fixture() - address = address_fixture() + actor = insert(:actor) + category = insert(:category) + address = insert(:address) valid_attrs = @event_valid_attrs @@ -94,11 +77,15 @@ defmodule Mobilizon.EventsTest do |> Map.put(:category_id, category.id) |> Map.put(:address_id, address.id) - assert {:ok, %Event{} = event} = Events.create_event(valid_attrs) - assert event.begins_on == DateTime.from_naive!(~N[2010-04-17 14:00:00.000000Z], "Etc/UTC") - assert event.description == "some description" - assert event.ends_on == DateTime.from_naive!(~N[2010-04-17 14:00:00.000000Z], "Etc/UTC") - assert event.title == "some title" + with {:ok, %Event{} = event} <- Events.create_event(valid_attrs) do + assert event.begins_on == DateTime.from_naive!(~N[2010-04-17 14:00:00.000000Z], "Etc/UTC") + assert event.description == "some description" + assert event.ends_on == DateTime.from_naive!(~N[2010-04-17 14:00:00.000000Z], "Etc/UTC") + assert event.title == "some title" + else + err -> + flunk("Failed to create an event #{inspect(err)}") + end end test "create_event/1 with invalid data returns error changeset" do @@ -135,27 +122,40 @@ defmodule Mobilizon.EventsTest do test "get_events_for_actor/3", %{actor: actor, event: event} do event1 = insert(:event, organizer_actor: actor) - assert {:ok, [event_found, event1_found], 2} = Events.get_events_for_actor(actor, 1, 10) + + with {:ok, events_found, 2} <- Events.get_events_for_actor(actor, 1, 10) do + event_ids = MapSet.new(events_found |> Enum.map(& &1.id)) + assert event_ids == MapSet.new([event.id, event1.id]) + else + err -> + flunk("Failed to get events for an actor #{inspect(err)}") + end end test "get_events_for_actor/3 with limited results", %{actor: actor, event: event} do event1 = insert(:event, organizer_actor: actor) - assert {:ok, [event_found], 2} = Events.get_events_for_actor(actor, 1, 1) + + with {:ok, [%Event{id: event_found_id}], 2} <- Events.get_events_for_actor(actor, 1, 1) do + assert event_found_id in [event.id, event1.id] + else + err -> + flunk("Failed to get limited events for an actor #{inspect(err)}") + end end - test "get_event_by_url/1 with valid url", %{actor: actor, event: event} do - assert event = Events.get_event_by_url(event.url) + test "get_event_by_url/1 with valid url", %{event: %Event{id: event_id, url: event_url}} do + assert event_id == Events.get_event_by_url(event_url).id end - test "get_event_by_url/1 with bad url", %{actor: actor, event: event} do - refute event == Events.get_event_by_url("not valid") + test "get_event_by_url/1 with bad url" do + assert is_nil(Events.get_event_by_url("not valid")) end - test "get_event_by_url!/1 with valid url", %{actor: actor, event: event} do - assert event = Events.get_event_by_url!(event.url) + test "get_event_by_url!/1 with valid url", %{event: %Event{id: event_id, url: event_url}} do + assert event_id == Events.get_event_by_url!(event_url).id end - test "get_event_by_url!/1 with bad url", %{actor: actor, event: event} do + test "get_event_by_url!/1 with bad url" do assert_raise Ecto.NoResultsError, fn -> Events.get_event_by_url!("not valid") end @@ -309,25 +309,35 @@ defmodule Mobilizon.EventsTest do {:ok, participant: participant, event: event, actor: actor} end - test "list_participants/0 returns all participants", %{participant: participant} do - assert [%Participant{} = participant] = Events.list_participants() + test "list_participants/0 returns all participants", %{ + participant: %Participant{event_id: participant_event_id, actor_id: participant_actor_id} + } do + assert [participant_event_id] == Events.list_participants() |> Enum.map(& &1.event_id) + assert [participant_actor_id] == Events.list_participants() |> Enum.map(& &1.actor_id) end test "get_participant!/1 returns the participant for a given event and given actor", %{ - event: %Event{id: event_id} = _event, - actor: %Actor{id: actor_id} = _actor + event: %Event{id: event_id}, + actor: %Actor{id: actor_id} } do - assert %Participant{event_id: event_id, actor_id: actor_id} = - _participant = Events.get_participant!(event_id, actor_id) + assert event_id == Events.get_participant!(event_id, actor_id).event_id + assert actor_id == Events.get_participant!(event_id, actor_id).actor_id end test "create_participant/1 with valid data creates a participant" do - actor = actor_fixture() - event = event_fixture() + actor = insert(:actor) + event = insert(:event) valid_attrs = Map.put(@valid_attrs, :event_id, event.id) valid_attrs = Map.put(valid_attrs, :actor_id, actor.id) - assert {:ok, %Participant{} = participant} = Events.create_participant(valid_attrs) - assert participant.role == 42 + + with {:ok, %Participant{} = participant} <- Events.create_participant(valid_attrs) do + assert participant.event_id == event.id + assert participant.actor_id == actor.id + assert participant.role == 42 + else + err -> + flunk("Failed to create a participant #{inspect(err)}") + end end test "create_participant/1 with invalid data returns error changeset" do @@ -337,9 +347,13 @@ defmodule Mobilizon.EventsTest do test "update_participant/2 with valid data updates the participant", %{ participant: participant } do - assert {:ok, participant} = Events.update_participant(participant, @update_attrs) - assert %Participant{} = participant - assert participant.role == 43 + with {:ok, %Participant{} = participant} <- + Events.update_participant(participant, @update_attrs) do + assert participant.role == 43 + else + err -> + flunk("Failed to update a participant #{inspect(err)}") + end end test "update_participant/2 with invalid data returns error changeset", %{ @@ -392,7 +406,7 @@ defmodule Mobilizon.EventsTest do } def session_fixture(attrs \\ %{}) do - event = event_fixture() + event = insert(:event) valid_attrs = Map.put(@valid_attrs, :event_id, event.id) {:ok, session} = @@ -414,7 +428,7 @@ defmodule Mobilizon.EventsTest do end test "create_session/1 with valid data creates a session" do - event = event_fixture() + event = insert(:event) valid_attrs = Map.put(@valid_attrs, :event_id, event.id) assert {:ok, %Session{} = session} = Events.create_session(valid_attrs) assert session.audios_urls == "some audios_urls" @@ -475,7 +489,7 @@ defmodule Mobilizon.EventsTest do @invalid_attrs %{color: nil, description: nil, name: nil} def track_fixture(attrs \\ %{}) do - event = event_fixture() + event = insert(:event) valid_attrs = Map.put(@valid_attrs, :event_id, event.id) {:ok, track} = @@ -497,7 +511,7 @@ defmodule Mobilizon.EventsTest do end test "create_track/1 with valid data creates a track" do - event = event_fixture() + event = insert(:event) valid_attrs = Map.put(@valid_attrs, :event_id, event.id) assert {:ok, %Track{} = track} = Events.create_track(valid_attrs) assert track.color == "some color" @@ -543,28 +557,29 @@ defmodule Mobilizon.EventsTest do @update_attrs %{text: "some updated text"} @invalid_attrs %{text: nil, url: nil} - def comment_fixture() do - insert(:comment) - end - test "list_comments/0 returns all comments" do - comment = comment_fixture() - comments = Events.list_comments() - assert comments = [comment] + %Comment{id: comment_id} = insert(:comment) + comment_ids = Events.list_comments() |> Enum.map(& &1.id) + assert comment_ids == [comment_id] end test "get_comment!/1 returns the comment with given id" do - comment = comment_fixture() - comment_fetched = Events.get_comment!(comment.id) - assert comment_fetched = comment + %Comment{id: comment_id} = insert(:comment) + comment_fetched = Events.get_comment!(comment_id) + assert comment_fetched.id == comment_id end test "create_comment/1 with valid data creates a comment" do - actor = actor_fixture() + actor = insert(:actor) comment_data = Map.merge(@valid_attrs, %{actor_id: actor.id}) - assert {:ok, %Comment{} = comment} = Events.create_comment(comment_data) - assert comment.text == "some text" - assert comment.actor_id == actor.id + + with {:ok, %Comment{} = comment} <- Events.create_comment(comment_data) do + assert comment.text == "some text" + assert comment.actor_id == actor.id + else + err -> + flunk("Failed to create a comment #{inspect(err)}") + end end test "create_comment/1 with invalid data returns error changeset" do @@ -572,27 +587,31 @@ defmodule Mobilizon.EventsTest do end test "update_comment/2 with valid data updates the comment" do - comment = comment_fixture() - assert {:ok, comment} = Events.update_comment(comment, @update_attrs) - assert %Comment{} = comment - assert comment.text == "some updated text" + comment = insert(:comment) + + with {:ok, %Comment{} = comment} <- Events.update_comment(comment, @update_attrs) do + assert comment.text == "some updated text" + else + err -> + flunk("Failed to update a comment #{inspect(err)}") + end end test "update_comment/2 with invalid data returns error changeset" do - comment = comment_fixture() + comment = insert(:comment) assert {:error, %Ecto.Changeset{}} = Events.update_comment(comment, @invalid_attrs) comment_fetched = Events.get_comment!(comment.id) assert comment = comment_fetched end test "delete_comment/1 deletes the comment" do - comment = comment_fixture() + comment = insert(:comment) assert {:ok, %Comment{}} = Events.delete_comment(comment) assert_raise Ecto.NoResultsError, fn -> Events.get_comment!(comment.id) end end test "change_comment/1 returns a comment changeset" do - comment = comment_fixture() + comment = insert(:comment) assert %Ecto.Changeset{} = Events.change_comment(comment) end end diff --git a/test/mobilizon/service/activitypub/activitypub_test.exs b/test/mobilizon/service/activitypub/activitypub_test.exs index cbe8cbe37..601b0895b 100644 --- a/test/mobilizon/service/activitypub/activitypub_test.exs +++ b/test/mobilizon/service/activitypub/activitypub_test.exs @@ -7,7 +7,6 @@ defmodule Mobilizon.Service.Activitypub.ActivitypubTest do alias Mobilizon.Actors.Actor alias Mobilizon.Actors alias Mobilizon.Service.ActivityPub - alias Mobilizon.Activity describe "fetching actor from it's url" do test "returns an actor from nickname" do @@ -40,12 +39,16 @@ defmodule Mobilizon.Service.Activitypub.ActivitypubTest do end describe "fetching an" do - test "event by url" do + test "object by url" do {:ok, object} = - ActivityPub.fetch_event_from_url("https://social.tcit.fr/@tcit/99908779444618462") + ActivityPub.fetch_object_from_url( + "https://social.tcit.fr/users/tcit/statuses/99908779444618462" + ) {:ok, object_again} = - ActivityPub.fetch_event_from_url("https://social.tcit.fr/@tcit/99908779444618462") + ActivityPub.fetch_object_from_url( + "https://social.tcit.fr/users/tcit/statuses/99908779444618462" + ) assert object == object_again end diff --git a/test/mobilizon_web/controllers/activity_pub_controller_test.exs b/test/mobilizon_web/controllers/activity_pub_controller_test.exs index 5b03f1981..4cd5e75ba 100644 --- a/test/mobilizon_web/controllers/activity_pub_controller_test.exs +++ b/test/mobilizon_web/controllers/activity_pub_controller_test.exs @@ -2,10 +2,9 @@ defmodule MobilizonWeb.ActivityPubControllerTest do use MobilizonWeb.ConnCase import Mobilizon.Factory alias MobilizonWeb.ActivityPub.{ActorView, ObjectView} - alias Mobilizon.{Repo, Actors, Actors.Actor} + alias Mobilizon.Actors alias Mobilizon.Service.ActivityPub - alias Mobilizon.Activity - import Logger + alias Mobilizon.Service.ActivityPub.Utils describe "/@:preferred_username" do test "it returns a json representation of the actor", %{conn: conn} do @@ -19,7 +18,6 @@ defmodule MobilizonWeb.ActivityPubControllerTest do actor = Actors.get_actor!(actor.id) assert json_response(conn, 200) == ActorView.render("actor.json", %{actor: actor}) - Logger.error(inspect(ActorView.render("actor.json", %{actor: actor}))) end end @@ -32,8 +30,8 @@ defmodule MobilizonWeb.ActivityPubControllerTest do |> put_req_header("accept", "application/activity+json") |> get("/events/#{event.uuid}") - assert json_response(conn, 200) == ObjectView.render("event.json", %{event: event}) - Logger.error(inspect(ObjectView.render("event.json", %{event: event}))) + assert json_response(conn, 200) == + ObjectView.render("event.json", %{event: event |> Utils.make_event_data()}) end test "it returns 404 for non-public events", %{conn: conn} do @@ -60,7 +58,7 @@ defmodule MobilizonWeb.ActivityPubControllerTest do assert "ok" == json_response(conn, 200) :timer.sleep(500) - assert ActivityPub.fetch_object_from_url(data["object"]["id"], :note) + assert ActivityPub.fetch_object_from_url(data["object"]["id"]) end end diff --git a/test/mobilizon_web/controllers/nodeinfo_controller_test.exs b/test/mobilizon_web/controllers/nodeinfo_controller_test.exs index 9443e2e00..b929cc2e0 100644 --- a/test/mobilizon_web/controllers/nodeinfo_controller_test.exs +++ b/test/mobilizon_web/controllers/nodeinfo_controller_test.exs @@ -26,12 +26,13 @@ defmodule MobilizonWeb.NodeInfoControllerTest do resp = json_response(conn, 200) - assert resp = %{ + assert resp == %{ "metadata" => %{"nodeName" => Keyword.get(@instance, :name)}, "openRegistrations" => Keyword.get(@instance, :registrations_open), "protocols" => ["activitypub"], "services" => %{"inbound" => [], "outbound" => []}, "software" => %{"name" => "mobilizon", "version" => Keyword.get(@instance, :version)}, + "usage" => %{"localComments" => 0, "localPosts" => 0, "users" => %{"total" => 0}}, "version" => "2.0" } end diff --git a/test/mobilizon_web/resolvers/actor_resolver_test.exs b/test/mobilizon_web/resolvers/actor_resolver_test.exs index 73ec0527b..f2a798ab8 100644 --- a/test/mobilizon_web/resolvers/actor_resolver_test.exs +++ b/test/mobilizon_web/resolvers/actor_resolver_test.exs @@ -1,9 +1,7 @@ defmodule MobilizonWeb.Resolvers.ActorResolverTest do use MobilizonWeb.ConnCase - alias Mobilizon.{Events, Actors} - alias Mobilizon.Actors.Actor + alias Mobilizon.Actors alias MobilizonWeb.AbsintheHelpers - import Mobilizon.Factory @valid_actor_params %{email: "test@test.tld", password: "testest", username: "test"} @non_existent_username "nonexistent" diff --git a/test/mobilizon_web/resolvers/event_resolver_test.exs b/test/mobilizon_web/resolvers/event_resolver_test.exs index 756dba5cd..1466a5066 100644 --- a/test/mobilizon_web/resolvers/event_resolver_test.exs +++ b/test/mobilizon_web/resolvers/event_resolver_test.exs @@ -52,7 +52,7 @@ defmodule MobilizonWeb.Resolvers.EventResolverTest do |> get("/api", AbsintheHelpers.query_skeleton(query, "event")) assert [%{"message" => "Argument \"uuid\" has invalid value \"bad uuid\"."}] = - json_response(res, 400)["errors"] + json_response(res, 200)["errors"] end test "list_participants_for_event/3 returns participants for an event", context do diff --git a/test/mobilizon_web/resolvers/user_resolver_test.exs b/test/mobilizon_web/resolvers/user_resolver_test.exs index 784250aa5..387284773 100644 --- a/test/mobilizon_web/resolvers/user_resolver_test.exs +++ b/test/mobilizon_web/resolvers/user_resolver_test.exs @@ -1,13 +1,11 @@ defmodule MobilizonWeb.Resolvers.UserResolverTest do use MobilizonWeb.ConnCase - alias Mobilizon.{Events, Actors} - alias Mobilizon.Actors.{Actor, User} + alias Mobilizon.Actors alias MobilizonWeb.AbsintheHelpers import Mobilizon.Factory use Bamboo.Test @valid_actor_params %{email: "test@test.tld", password: "testest", username: "test"} - @non_existent_username "nonexistent" describe "User Resolver" do test "find_user/3 returns an user by it's id", context do @@ -161,7 +159,7 @@ defmodule MobilizonWeb.Resolvers.UserResolverTest do end test "test validate_user/3 with invalid token doesn't validate an user", context do - {:ok, actor} = Actors.register(@valid_actor_params) + {:ok, _actor} = Actors.register(@valid_actor_params) mutation = """ mutation { @@ -219,7 +217,7 @@ defmodule MobilizonWeb.Resolvers.UserResolverTest do test "test resend_confirmation_email/3 with invalid email resends an validation email", context do - {:ok, actor} = Actors.register(@valid_actor_params) + {:ok, _actor} = Actors.register(@valid_actor_params) mutation = """ mutation {