diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/mix/tasks/pleroma/instance.ex | 16 | ||||
| -rw-r--r-- | lib/mix/tasks/pleroma/sample_config.eex | 2 | ||||
| -rw-r--r-- | lib/mix/tasks/pleroma/sample_psql.eex | 6 | ||||
| -rw-r--r-- | lib/mix/tasks/pleroma/user.ex | 18 | ||||
| -rw-r--r-- | lib/pleroma/plugs/federating_plug.ex | 3 | ||||
| -rw-r--r-- | lib/pleroma/user.ex | 5 | ||||
| -rw-r--r-- | lib/pleroma/user/info.ex | 5 | ||||
| -rw-r--r-- | lib/pleroma/web/channels/user_socket.ex | 4 | ||||
| -rw-r--r-- | lib/pleroma/web/endpoint.ex | 2 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 135 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/mastodon_socket.ex | 81 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/websocket_handler.ex | 120 | ||||
| -rw-r--r-- | lib/pleroma/web/streamer.ex | 22 | ||||
| -rw-r--r-- | lib/pleroma/web/twitter_api/twitter_api_controller.ex | 126 | ||||
| -rw-r--r-- | lib/pleroma/web/twitter_api/views/activity_view.ex | 6 | ||||
| -rw-r--r-- | lib/pleroma/web/web_finger/web_finger_controller.ex | 4 | 
16 files changed, 362 insertions, 193 deletions
diff --git a/lib/mix/tasks/pleroma/instance.ex b/lib/mix/tasks/pleroma/instance.ex index 3be856115..02e1ce27d 100644 --- a/lib/mix/tasks/pleroma/instance.ex +++ b/lib/mix/tasks/pleroma/instance.ex @@ -58,12 +58,15 @@ defmodule Mix.Tasks.Pleroma.Instance do      proceed? = Enum.empty?(will_overwrite) or Keyword.get(options, :force, false)      unless not proceed? do -      domain = -        Common.get_option( -          options, -          :domain, -          "What domain will your instance use? (e.g pleroma.soykaf.com)" -        ) +      [domain, port | _] = +        String.split( +          Common.get_option( +            options, +            :domain, +            "What domain will your instance use? (e.g pleroma.soykaf.com)" +          ), +          ":" +        ) ++ [443]        name =          Common.get_option( @@ -104,6 +107,7 @@ defmodule Mix.Tasks.Pleroma.Instance do          EEx.eval_file(            "sample_config.eex" |> Path.expand(__DIR__),            domain: domain, +          port: port,            email: email,            name: name,            dbhost: dbhost, diff --git a/lib/mix/tasks/pleroma/sample_config.eex b/lib/mix/tasks/pleroma/sample_config.eex index 0cd572797..740b9f8d1 100644 --- a/lib/mix/tasks/pleroma/sample_config.eex +++ b/lib/mix/tasks/pleroma/sample_config.eex @@ -6,7 +6,7 @@  use Mix.Config  config :pleroma, Pleroma.Web.Endpoint, -   url: [host: "<%= domain %>", scheme: "https", port: 443], +   url: [host: "<%= domain %>", scheme: "https", port: <%= port %>],     secret_key_base: "<%= secret %>"  config :pleroma, :instance, diff --git a/lib/mix/tasks/pleroma/sample_psql.eex b/lib/mix/tasks/pleroma/sample_psql.eex index c89b34ef2..f0ac05e57 100644 --- a/lib/mix/tasks/pleroma/sample_psql.eex +++ b/lib/mix/tasks/pleroma/sample_psql.eex @@ -1,6 +1,6 @@ -CREATE USER pleroma WITH ENCRYPTED PASSWORD '<%= dbpass %>'; -CREATE DATABASE pleroma_dev OWNER pleroma; -\c pleroma_dev; +CREATE USER <%= dbuser %> WITH ENCRYPTED PASSWORD '<%= dbpass %>'; +CREATE DATABASE <%= dbname %> OWNER <%= dbuser %>; +\c <%= dbname %>;  --Extensions made by ecto.migrate that need superuser access  CREATE EXTENSION IF NOT EXISTS citext;  CREATE EXTENSION IF NOT EXISTS pg_trgm; diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index fe6e6935f..3d30e3a81 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -94,16 +94,14 @@ defmodule Mix.Tasks.Pleroma.User do      unless not proceed? do        Common.start_pleroma() -      params = -        %{ -          nickname: nickname, -          email: email, -          password: password, -          password_confirmation: password, -          name: name, -          bio: bio -        } -        |> IO.inspect() +      params = %{ +        nickname: nickname, +        email: email, +        password: password, +        password_confirmation: password, +        name: name, +        bio: bio +      }        user = User.register_changeset(%User{}, params)        Repo.insert!(user) diff --git a/lib/pleroma/plugs/federating_plug.ex b/lib/pleroma/plugs/federating_plug.ex index f0442ca15..b5326d97b 100644 --- a/lib/pleroma/plugs/federating_plug.ex +++ b/lib/pleroma/plugs/federating_plug.ex @@ -11,7 +11,8 @@ defmodule Pleroma.Web.FederatingPlug do      else        conn        |> put_status(404) -      |> Phoenix.Controller.render(Pleroma.Web.ErrorView, "404.json") +      |> Phoenix.Controller.put_view(Pleroma.Web.ErrorView) +      |> Phoenix.Controller.render("404.json")        |> halt()      end    end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 49928bc13..3ad1ab87a 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -838,7 +838,7 @@ defmodule Pleroma.User do      do: tag(User.get_by_nickname(nickname), tags)    def tag(%User{} = user, tags), -    do: update_tags(user, Enum.uniq(user.tags ++ normalize_tags(tags))) +    do: update_tags(user, Enum.uniq((user.tags || []) ++ normalize_tags(tags)))    def untag(user_identifiers, tags) when is_list(user_identifiers) do      Repo.transaction(fn -> @@ -849,7 +849,8 @@ defmodule Pleroma.User do    def untag(nickname, tags) when is_binary(nickname),      do: untag(User.get_by_nickname(nickname), tags) -  def untag(%User{} = user, tags), do: update_tags(user, user.tags -- normalize_tags(tags)) +  def untag(%User{} = user, tags), +    do: update_tags(user, (user.tags || []) -- normalize_tags(tags))    defp update_tags(%User{} = user, new_tags) do      {:ok, updated_user} = diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index d81b45b8d..a3785447c 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -149,9 +149,12 @@ defmodule Pleroma.User.Info do      ])    end -  def mastodon_settings_update(info, params) do +  def mastodon_settings_update(info, settings) do +    params = %{settings: settings} +      info      |> cast(params, [:settings]) +    |> validate_required([:settings])    end    def set_source_data(info, source_data) do diff --git a/lib/pleroma/web/channels/user_socket.ex b/lib/pleroma/web/channels/user_socket.ex index 07ddee169..9918d3b49 100644 --- a/lib/pleroma/web/channels/user_socket.ex +++ b/lib/pleroma/web/channels/user_socket.ex @@ -6,10 +6,6 @@ defmodule Pleroma.Web.UserSocket do    # channel "room:*", Pleroma.Web.RoomChannel    channel("chat:*", Pleroma.Web.ChatChannel) -  ## Transports -  transport(:websocket, Phoenix.Transports.WebSocket) -  # transport :longpoll, Phoenix.Transports.LongPoll -    # Socket params are passed from the client and can    # be used to verify and authenticate a user. After    # verification, you can put default assigns into diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex index c5f9d51d9..e52667c72 100644 --- a/lib/pleroma/web/endpoint.ex +++ b/lib/pleroma/web/endpoint.ex @@ -3,8 +3,6 @@ defmodule Pleroma.Web.Endpoint do    socket("/socket", Pleroma.Web.UserSocket) -  socket("/api/v1", Pleroma.Web.MastodonAPI.MastodonSocket) -    # Serve at "/" the static files from "priv/static" directory.    #    # You should set gzip to true if you are running phoenix.digest diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 0414d73d8..665b75437 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -226,7 +226,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do      conn      |> add_link_headers(:home_timeline, activities) -    |> render(StatusView, "index.json", %{activities: activities, for: user, as: :activity}) +    |> put_view(StatusView) +    |> render("index.json", %{activities: activities, for: user, as: :activity})    end    def public_timeline(%{assigns: %{user: user}} = conn, params) do @@ -244,7 +245,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do      conn      |> add_link_headers(:public_timeline, activities, false, %{"local" => local_only}) -    |> render(StatusView, "index.json", %{activities: activities, for: user, as: :activity}) +    |> put_view(StatusView) +    |> render("index.json", %{activities: activities, for: user, as: :activity})    end    def user_statuses(%{assigns: %{user: reading_user}} = conn, params) do @@ -259,7 +261,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do        conn        |> add_link_headers(:user_statuses, activities, params["id"]) -      |> render(StatusView, "index.json", %{ +      |> put_view(StatusView) +      |> render("index.json", %{          activities: activities,          for: reading_user,          as: :activity @@ -278,13 +281,16 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do      conn      |> add_link_headers(:dm_timeline, activities) -    |> render(StatusView, "index.json", %{activities: activities, for: user, as: :activity}) +    |> put_view(StatusView) +    |> render("index.json", %{activities: activities, for: user, as: :activity})    end    def get_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do      with %Activity{} = activity <- Repo.get(Activity, id),           true <- ActivityPub.visible_for_user?(activity, user) do -      try_render(conn, StatusView, "status.json", %{activity: activity, for: user}) +      conn +      |> put_view(StatusView) +      |> try_render("status.json", %{activity: activity, for: user})      end    end @@ -347,7 +353,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do      {:ok, activity} =        Cachex.fetch!(:idempotency_cache, idempotency_key, fn _ -> CommonAPI.post(user, params) end) -    try_render(conn, StatusView, "status.json", %{activity: activity, for: user, as: :activity}) +    conn +    |> put_view(StatusView) +    |> try_render("status.json", %{activity: activity, for: user, as: :activity})    end    def delete_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do @@ -363,28 +371,36 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do    def reblog_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do      with {:ok, announce, _activity} <- CommonAPI.repeat(ap_id_or_id, user) do -      try_render(conn, StatusView, "status.json", %{activity: announce, for: user, as: :activity}) +      conn +      |> put_view(StatusView) +      |> try_render("status.json", %{activity: announce, for: user, as: :activity})      end    end    def unreblog_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do      with {:ok, _unannounce, %{data: %{"id" => id}}} <- CommonAPI.unrepeat(ap_id_or_id, user),           %Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id) do -      try_render(conn, StatusView, "status.json", %{activity: activity, for: user, as: :activity}) +      conn +      |> put_view(StatusView) +      |> try_render("status.json", %{activity: activity, for: user, as: :activity})      end    end    def fav_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do      with {:ok, _fav, %{data: %{"id" => id}}} <- CommonAPI.favorite(ap_id_or_id, user),           %Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id) do -      try_render(conn, StatusView, "status.json", %{activity: activity, for: user, as: :activity}) +      conn +      |> put_view(StatusView) +      |> try_render("status.json", %{activity: activity, for: user, as: :activity})      end    end    def unfav_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do      with {:ok, _, _, %{data: %{"id" => id}}} <- CommonAPI.unfavorite(ap_id_or_id, user),           %Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id) do -      try_render(conn, StatusView, "status.json", %{activity: activity, for: user, as: :activity}) +      conn +      |> put_view(StatusView) +      |> try_render("status.json", %{activity: activity, for: user, as: :activity})      end    end @@ -433,7 +449,10 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do      id = List.wrap(id)      q = from(u in User, where: u.id in ^id)      targets = Repo.all(q) -    render(conn, AccountView, "relationships.json", %{user: user, targets: targets}) + +    conn +    |> put_view(AccountView) +    |> render("relationships.json", %{user: user, targets: targets})    end    # Instead of returning a 400 when no "id" params is present, Mastodon returns an empty array. @@ -452,7 +471,10 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do          |> Repo.update()        attachment_data = Map.put(new_data, "id", object.id) -      render(conn, StatusView, "attachment.json", %{attachment: attachment_data}) + +      conn +      |> put_view(StatusView) +      |> render("attachment.json", %{attachment: attachment_data})      end    end @@ -463,7 +485,10 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do               description: Map.get(data, "description")             ) do        attachment_data = Map.put(object.data, "id", object.id) -      render(conn, StatusView, "attachment.json", %{attachment: attachment_data}) + +      conn +      |> put_view(StatusView) +      |> render("attachment.json", %{attachment: attachment_data})      end    end @@ -471,7 +496,10 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do      with %Activity{data: %{"object" => %{"likes" => likes}}} <- Repo.get(Activity, id) do        q = from(u in User, where: u.ap_id in ^likes)        users = Repo.all(q) -      render(conn, AccountView, "accounts.json", %{users: users, as: :user}) + +      conn +      |> put_view(AccountView) +      |> render(AccountView, "accounts.json", %{users: users, as: :user})      else        _ -> json(conn, [])      end @@ -481,7 +509,10 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do      with %Activity{data: %{"object" => %{"announcements" => announces}}} <- Repo.get(Activity, id) do        q = from(u in User, where: u.ap_id in ^announces)        users = Repo.all(q) -      render(conn, AccountView, "accounts.json", %{users: users, as: :user}) + +      conn +      |> put_view(AccountView) +      |> render("accounts.json", %{users: users, as: :user})      else        _ -> json(conn, [])      end @@ -503,7 +534,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do      conn      |> add_link_headers(:hashtag_timeline, activities, params["tag"], %{"local" => local_only}) -    |> render(StatusView, "index.json", %{activities: activities, for: user, as: :activity}) +    |> put_view(StatusView) +    |> render("index.json", %{activities: activities, for: user, as: :activity})    end    def followers(%{assigns: %{user: for_user}} = conn, %{"id" => id}) do @@ -516,7 +548,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do            true -> followers          end -      render(conn, AccountView, "accounts.json", %{users: followers, as: :user}) +      conn +      |> put_view(AccountView) +      |> render("accounts.json", %{users: followers, as: :user})      end    end @@ -530,13 +564,17 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do            true -> followers          end -      render(conn, AccountView, "accounts.json", %{users: followers, as: :user}) +      conn +      |> put_view(AccountView) +      |> render("accounts.json", %{users: followers, as: :user})      end    end    def follow_requests(%{assigns: %{user: followed}} = conn, _params) do      with {:ok, follow_requests} <- User.get_follow_requests(followed) do -      render(conn, AccountView, "accounts.json", %{users: follow_requests, as: :user}) +      conn +      |> put_view(AccountView) +      |> render("accounts.json", %{users: follow_requests, as: :user})      end    end @@ -552,7 +590,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do               object: follow_activity.data["id"],               type: "Accept"             }) do -      render(conn, AccountView, "relationship.json", %{user: followed, target: follower}) +      conn +      |> put_view(AccountView) +      |> render("relationship.json", %{user: followed, target: follower})      else        {:error, message} ->          conn @@ -572,7 +612,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do               object: follow_activity.data["id"],               type: "Reject"             }) do -      render(conn, AccountView, "relationship.json", %{user: followed, target: follower}) +      conn +      |> put_view(AccountView) +      |> render("relationship.json", %{user: followed, target: follower})      else        {:error, message} ->          conn @@ -591,7 +633,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do               follower,               followed             ) do -      render(conn, AccountView, "relationship.json", %{user: follower, target: followed}) +      conn +      |> put_view(AccountView) +      |> render("relationship.json", %{user: follower, target: followed})      else        {:error, message} ->          conn @@ -604,7 +648,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do      with %User{} = followed <- Repo.get_by(User, nickname: uri),           {:ok, follower} <- User.maybe_direct_follow(follower, followed),           {:ok, _activity} <- ActivityPub.follow(follower, followed) do -      render(conn, AccountView, "account.json", %{user: followed, for: follower}) +      conn +      |> put_view(AccountView) +      |> render("account.json", %{user: followed, for: follower})      else        {:error, message} ->          conn @@ -617,7 +663,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do      with %User{} = followed <- Repo.get(User, id),           {:ok, _activity} <- ActivityPub.unfollow(follower, followed),           {:ok, follower, _} <- User.unfollow(follower, followed) do -      render(conn, AccountView, "relationship.json", %{user: follower, target: followed}) +      conn +      |> put_view(AccountView) +      |> render("relationship.json", %{user: follower, target: followed})      end    end @@ -625,7 +673,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do      with %User{} = blocked <- Repo.get(User, id),           {:ok, blocker} <- User.block(blocker, blocked),           {:ok, _activity} <- ActivityPub.block(blocker, blocked) do -      render(conn, AccountView, "relationship.json", %{user: blocker, target: blocked}) +      conn +      |> put_view(AccountView) +      |> render("relationship.json", %{user: blocker, target: blocked})      else        {:error, message} ->          conn @@ -638,7 +688,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do      with %User{} = blocked <- Repo.get(User, id),           {:ok, blocker} <- User.unblock(blocker, blocked),           {:ok, _activity} <- ActivityPub.unblock(blocker, blocked) do -      render(conn, AccountView, "relationship.json", %{user: blocker, target: blocked}) +      conn +      |> put_view(AccountView) +      |> render("relationship.json", %{user: blocker, target: blocked})      else        {:error, message} ->          conn @@ -763,7 +815,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do        |> Enum.reverse()      conn -    |> render(StatusView, "index.json", %{activities: activities, for: user, as: :activity}) +    |> put_view(StatusView) +    |> render("index.json", %{activities: activities, for: user, as: :activity})    end    def get_lists(%{assigns: %{user: user}} = conn, opts) do @@ -831,7 +884,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do    def list_accounts(%{assigns: %{user: user}} = conn, %{"id" => id}) do      with %Pleroma.List{} = list <- Pleroma.List.get(id, user),           {:ok, users} = Pleroma.List.get_following(list) do -      render(conn, AccountView, "accounts.json", %{users: users, as: :user}) +      conn +      |> put_view(AccountView) +      |> render("accounts.json", %{users: users, as: :user})      end    end @@ -864,7 +919,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do          |> Enum.reverse()        conn -      |> render(StatusView, "index.json", %{activities: activities, for: user, as: :activity}) +      |> put_view(StatusView) +      |> render("index.json", %{activities: activities, for: user, as: :activity})      else        _e ->          conn @@ -929,7 +985,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do              ]            },            settings: -            Map.get(user.info, :settings) || +            user.info.settings ||                %{                  onboarded: true,                  home: %{ @@ -968,7 +1024,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do        conn        |> put_layout(false) -      |> render(MastodonView, "index.html", %{initial_state: initial_state}) +      |> put_view(MastodonView) +      |> render("index.html", %{initial_state: initial_state})      else        conn        |> redirect(to: "/web/login") @@ -978,13 +1035,15 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do    def put_settings(%{assigns: %{user: user}} = conn, %{"data" => settings} = _params) do      info_cng = User.Info.mastodon_settings_update(user.info, settings) -    with changeset <- User.update_changeset(user), +    with changeset <- Ecto.Changeset.change(user),           changeset <- Ecto.Changeset.put_embed(changeset, :info, info_cng),           {:ok, _user} <- User.update_and_set_cache(changeset) do        json(conn, %{})      else        e -> -        json(conn, %{error: inspect(e)}) +        conn +        |> put_resp_content_type("application/json") +        |> send_resp(500, Jason.encode!(%{"error" => inspect(e)}))      end    end @@ -1039,7 +1098,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do      Logger.debug("Unimplemented, returning unmodified relationship")      with %User{} = target <- Repo.get(User, id) do -      render(conn, AccountView, "relationship.json", %{user: user, target: target}) +      conn +      |> put_view(AccountView) +      |> render("relationship.json", %{user: user, target: target})      end    end @@ -1240,9 +1301,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do      end    end -  def try_render(conn, renderer, target, params) +  def try_render(conn, target, params)        when is_binary(target) do -    res = render(conn, renderer, target, params) +    res = render(conn, target, params)      if res == nil do        conn @@ -1253,7 +1314,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do      end    end -  def try_render(conn, _, _, _) do +  def try_render(conn, _, _) do      conn      |> put_status(501)      |> json(%{error: "Can't display this activity"}) diff --git a/lib/pleroma/web/mastodon_api/mastodon_socket.ex b/lib/pleroma/web/mastodon_api/mastodon_socket.ex deleted file mode 100644 index 755ac5730..000000000 --- a/lib/pleroma/web/mastodon_api/mastodon_socket.ex +++ /dev/null @@ -1,81 +0,0 @@ -defmodule Pleroma.Web.MastodonAPI.MastodonSocket do -  use Phoenix.Socket - -  alias Pleroma.Web.OAuth.Token -  alias Pleroma.{User, Repo} - -  transport( -    :websocket, -    Phoenix.Transports.WebSocket.Raw, -    # We never receive data. -    timeout: :infinity -  ) - -  @spec connect(params :: map(), Phoenix.Socket.t()) :: {:ok, Phoenix.Socket.t()} | :error -  def connect(%{"access_token" => token} = params, socket) do -    with %Token{user_id: user_id} <- Repo.get_by(Token, token: token), -         %User{} = user <- Repo.get(User, user_id), -         stream -         when stream in [ -                "public", -                "public:local", -                "public:media", -                "public:local:media", -                "user", -                "direct", -                "list", -                "hashtag" -              ] <- params["stream"] do -      topic = -        case stream do -          "hashtag" -> "hashtag:#{params["tag"]}" -          "list" -> "list:#{params["list"]}" -          _ -> stream -        end - -      socket = -        socket -        |> assign(:topic, topic) -        |> assign(:user, user) - -      Pleroma.Web.Streamer.add_socket(topic, socket) -      {:ok, socket} -    else -      _e -> :error -    end -  end - -  def connect(%{"stream" => stream} = params, socket) -      when stream in ["public", "public:local", "hashtag"] do -    topic = -      case stream do -        "hashtag" -> "hashtag:#{params["tag"]}" -        _ -> stream -      end - -    socket = -      socket -      |> assign(:topic, topic) - -    Pleroma.Web.Streamer.add_socket(topic, socket) -    {:ok, socket} -  end - -  def connect(_params, _socket), do: :error - -  def id(_), do: nil - -  def handle(:text, message, _state) do -    # | :ok -    # | state -    # | {:text, message} -    # | {:text, message, state} -    # | {:close, "Goodbye!"} -    {:text, message} -  end - -  def handle(:closed, _, %{socket: socket}) do -    topic = socket.assigns[:topic] -    Pleroma.Web.Streamer.remove_socket(topic, socket) -  end -end diff --git a/lib/pleroma/web/mastodon_api/websocket_handler.ex b/lib/pleroma/web/mastodon_api/websocket_handler.ex new file mode 100644 index 000000000..11e0e1696 --- /dev/null +++ b/lib/pleroma/web/mastodon_api/websocket_handler.ex @@ -0,0 +1,120 @@ +defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do +  require Logger + +  alias Pleroma.Web.OAuth.Token +  alias Pleroma.{User, Repo} + +  @behaviour :cowboy_websocket_handler + +  @streams [ +    "public", +    "public:local", +    "public:media", +    "public:local:media", +    "user", +    "direct", +    "list", +    "hashtag" +  ] +  @anonymous_streams ["public", "public:local", "hashtag"] + +  # Handled by periodic keepalive in Pleroma.Web.Streamer. +  @timeout :infinity + +  def init(_type, _req, _opts) do +    {:upgrade, :protocol, :cowboy_websocket} +  end + +  def websocket_init(_type, req, _opts) do +    with {qs, req} <- :cowboy_req.qs(req), +         params <- :cow_qs.parse_qs(qs), +         access_token <- List.keyfind(params, "access_token", 0), +         {_, stream} <- List.keyfind(params, "stream", 0), +         {:ok, user} <- allow_request(stream, access_token), +         topic when is_binary(topic) <- expand_topic(stream, params) do +      send(self(), :subscribe) +      {:ok, req, %{user: user, topic: topic}, @timeout} +    else +      {:error, code} -> +        Logger.debug("#{__MODULE__} denied connection: #{inspect(code)} - #{inspect(req)}") +        {:ok, req} = :cowboy_req.reply(code, req) +        {:shutdown, req} + +      error -> +        Logger.debug("#{__MODULE__} denied connection: #{inspect(error)} - #{inspect(req)}") +        {:shutdown, req} +    end +  end + +  # We never receive messages. +  def websocket_handle(_frame, req, state) do +    {:ok, req, state} +  end + +  def websocket_info(:subscribe, req, state) do +    Logger.debug( +      "#{__MODULE__} accepted websocket connection for user #{ +        (state.user || %{id: "anonymous"}).id +      }, topic #{state.topic}" +    ) + +    Pleroma.Web.Streamer.add_socket(state.topic, streamer_socket(state)) +    {:ok, req, state} +  end + +  def websocket_info({:text, message}, req, state) do +    {:reply, {:text, message}, req, state} +  end + +  def websocket_terminate(reason, _req, state) do +    Logger.debug( +      "#{__MODULE__} terminating websocket connection for user #{ +        (state.user || %{id: "anonymous"}).id +      }, topic #{state.topic || "?"}: #{inspect(reason)}" +    ) + +    Pleroma.Web.Streamer.remove_socket(state.topic, streamer_socket(state)) +    :ok +  end + +  # Public streams without authentication. +  defp allow_request(stream, nil) when stream in @anonymous_streams do +    {:ok, nil} +  end + +  # Authenticated streams. +  defp allow_request(stream, {"access_token", access_token}) when stream in @streams do +    with %Token{user_id: user_id} <- Repo.get_by(Token, token: access_token), +         user = %User{} <- Repo.get(User, user_id) do +      {:ok, user} +    else +      _ -> {:error, 403} +    end +  end + +  # Not authenticated. +  defp allow_request(stream, _) when stream in @streams, do: {:error, 403} + +  # No matching stream. +  defp allow_request(_, _), do: {:error, 404} + +  defp expand_topic("hashtag", params) do +    case List.keyfind(params, "tag", 0) do +      {_, tag} -> "hashtag:#{tag}" +      _ -> nil +    end +  end + +  defp expand_topic("list", params) do +    case List.keyfind(params, "list", 0) do +      {_, list} -> "list:#{list}" +      _ -> nil +    end +  end + +  defp expand_topic(topic, _), do: topic + +  defp streamer_socket(state) do +    %{transport_pid: self(), assigns: state} +  end +end diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex index 29c44e9d5..e1eecba4d 100644 --- a/lib/pleroma/web/streamer.ex +++ b/lib/pleroma/web/streamer.ex @@ -4,17 +4,9 @@ defmodule Pleroma.Web.Streamer do    alias Pleroma.{User, Notification, Activity, Object, Repo}    alias Pleroma.Web.ActivityPub.ActivityPub -  def init(args) do -    {:ok, args} -  end +  @keepalive_interval :timer.seconds(30)    def start_link do -    spawn(fn -> -      # 30 seconds -      Process.sleep(1000 * 30) -      GenServer.cast(__MODULE__, %{action: :ping}) -    end) -      GenServer.start_link(__MODULE__, %{}, name: __MODULE__)    end @@ -30,6 +22,16 @@ defmodule Pleroma.Web.Streamer do      GenServer.cast(__MODULE__, %{action: :stream, topic: topic, item: item})    end +  def init(args) do +    spawn(fn -> +      # 30 seconds +      Process.sleep(@keepalive_interval) +      GenServer.cast(__MODULE__, %{action: :ping}) +    end) + +    {:ok, args} +  end +    def handle_cast(%{action: :ping}, topics) do      Map.values(topics)      |> List.flatten() @@ -40,7 +42,7 @@ defmodule Pleroma.Web.Streamer do      spawn(fn ->        # 30 seconds -      Process.sleep(1000 * 30) +      Process.sleep(@keepalive_interval)        GenServer.cast(__MODULE__, %{action: :ping})      end) diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index 38eff8191..327620302 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -17,7 +17,10 @@ defmodule Pleroma.Web.TwitterAPI.Controller do    def verify_credentials(%{assigns: %{user: user}} = conn, _params) do      token = Phoenix.Token.sign(conn, "user socket", user.id) -    render(conn, UserView, "show.json", %{user: user, token: token}) + +    conn +    |> put_view(UserView) +    |> render("show.json", %{user: user, token: token})    end    def status_update(%{assigns: %{user: user}} = conn, %{"status" => _} = status_data) do @@ -58,7 +61,8 @@ defmodule Pleroma.Web.TwitterAPI.Controller do      activities = ActivityPub.fetch_public_activities(params)      conn -    |> render(ActivityView, "index.json", %{activities: activities, for: user}) +    |> put_view(ActivityView) +    |> render("index.json", %{activities: activities, for: user})    end    def public_timeline(%{assigns: %{user: user}} = conn, params) do @@ -71,7 +75,8 @@ defmodule Pleroma.Web.TwitterAPI.Controller do      activities = ActivityPub.fetch_public_activities(params)      conn -    |> render(ActivityView, "index.json", %{activities: activities, for: user}) +    |> put_view(ActivityView) +    |> render("index.json", %{activities: activities, for: user})    end    def friends_timeline(%{assigns: %{user: user}} = conn, params) do @@ -86,16 +91,22 @@ defmodule Pleroma.Web.TwitterAPI.Controller do        |> ActivityPub.contain_timeline(user)      conn -    |> render(ActivityView, "index.json", %{activities: activities, for: user}) +    |> put_view(ActivityView) +    |> render("index.json", %{activities: activities, for: user})    end    def show_user(conn, params) do      with {:ok, shown} <- TwitterAPI.get_user(params) do -      if user = conn.assigns.user do -        render(conn, UserView, "show.json", %{user: shown, for: user}) -      else -        render(conn, UserView, "show.json", %{user: shown}) -      end +      params = +        if user = conn.assigns.user do +          %{user: shown, for: user} +        else +          %{user: shown} +        end + +      conn +      |> put_view(UserView) +      |> render("show.json", params)      else        {:error, msg} ->          bad_request_reply(conn, msg) @@ -108,7 +119,8 @@ defmodule Pleroma.Web.TwitterAPI.Controller do          activities = ActivityPub.fetch_user_activities(target_user, user, params)          conn -        |> render(ActivityView, "index.json", %{activities: activities, for: user}) +        |> put_view(ActivityView) +        |> render("index.json", %{activities: activities, for: user})        {:error, msg} ->          bad_request_reply(conn, msg) @@ -124,7 +136,8 @@ defmodule Pleroma.Web.TwitterAPI.Controller do      activities = ActivityPub.fetch_activities([user.ap_id], params)      conn -    |> render(ActivityView, "index.json", %{activities: activities, for: user}) +    |> put_view(ActivityView) +    |> render("index.json", %{activities: activities, for: user})    end    def dm_timeline(%{assigns: %{user: user}} = conn, params) do @@ -137,14 +150,16 @@ defmodule Pleroma.Web.TwitterAPI.Controller do      activities = Repo.all(query)      conn -    |> render(ActivityView, "index.json", %{activities: activities, for: user}) +    |> put_view(ActivityView) +    |> render("index.json", %{activities: activities, for: user})    end    def notifications(%{assigns: %{user: user}} = conn, params) do      notifications = Notification.for_user(user, params)      conn -    |> render(NotificationView, "notification.json", %{notifications: notifications, for: user}) +    |> put_view(NotificationView) +    |> render("notification.json", %{notifications: notifications, for: user})    end    def notifications_read(%{assigns: %{user: user}} = conn, %{"latest_id" => latest_id} = params) do @@ -153,7 +168,8 @@ defmodule Pleroma.Web.TwitterAPI.Controller do      notifications = Notification.for_user(user, params)      conn -    |> render(NotificationView, "notification.json", %{notifications: notifications, for: user}) +    |> put_view(NotificationView) +    |> render("notification.json", %{notifications: notifications, for: user})    end    def notifications_read(%{assigns: %{user: _user}} = conn, _) do @@ -163,7 +179,9 @@ defmodule Pleroma.Web.TwitterAPI.Controller do    def follow(%{assigns: %{user: user}} = conn, params) do      case TwitterAPI.follow(user, params) do        {:ok, user, followed, _activity} -> -        render(conn, UserView, "show.json", %{user: followed, for: user}) +        conn +        |> put_view(UserView) +        |> render("show.json", %{user: followed, for: user})        {:error, msg} ->          forbidden_json_reply(conn, msg) @@ -173,7 +191,9 @@ defmodule Pleroma.Web.TwitterAPI.Controller do    def block(%{assigns: %{user: user}} = conn, params) do      case TwitterAPI.block(user, params) do        {:ok, user, blocked} -> -        render(conn, UserView, "show.json", %{user: blocked, for: user}) +        conn +        |> put_view(UserView) +        |> render("show.json", %{user: blocked, for: user})        {:error, msg} ->          forbidden_json_reply(conn, msg) @@ -183,7 +203,9 @@ defmodule Pleroma.Web.TwitterAPI.Controller do    def unblock(%{assigns: %{user: user}} = conn, params) do      case TwitterAPI.unblock(user, params) do        {:ok, user, blocked} -> -        render(conn, UserView, "show.json", %{user: blocked, for: user}) +        conn +        |> put_view(UserView) +        |> render("show.json", %{user: blocked, for: user})        {:error, msg} ->          forbidden_json_reply(conn, msg) @@ -192,14 +214,18 @@ defmodule Pleroma.Web.TwitterAPI.Controller do    def delete_post(%{assigns: %{user: user}} = conn, %{"id" => id}) do      with {:ok, activity} <- TwitterAPI.delete(user, id) do -      render(conn, ActivityView, "activity.json", %{activity: activity, for: user}) +      conn +      |> put_view(ActivityView) +      |> render("activity.json", %{activity: activity, for: user})      end    end    def unfollow(%{assigns: %{user: user}} = conn, params) do      case TwitterAPI.unfollow(user, params) do        {:ok, user, unfollowed} -> -        render(conn, UserView, "show.json", %{user: unfollowed, for: user}) +        conn +        |> put_view(UserView) +        |> render("show.json", %{user: unfollowed, for: user})        {:error, msg} ->          forbidden_json_reply(conn, msg) @@ -209,7 +235,9 @@ defmodule Pleroma.Web.TwitterAPI.Controller do    def fetch_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do      with %Activity{} = activity <- Repo.get(Activity, id),           true <- ActivityPub.visible_for_user?(activity, user) do -      render(conn, ActivityView, "activity.json", %{activity: activity, for: user}) +      conn +      |> put_view(ActivityView) +      |> render("activity.json", %{activity: activity, for: user})      end    end @@ -223,7 +251,8 @@ defmodule Pleroma.Web.TwitterAPI.Controller do               "user" => user             }) do        conn -      |> render(ActivityView, "index.json", %{activities: activities, for: user}) +      |> put_view(ActivityView) +      |> render("index.json", %{activities: activities, for: user})      end    end @@ -290,34 +319,44 @@ defmodule Pleroma.Web.TwitterAPI.Controller do    def favorite(%{assigns: %{user: user}} = conn, %{"id" => id}) do      with {_, {:ok, id}} <- {:param_cast, Ecto.Type.cast(:integer, id)},           {:ok, activity} <- TwitterAPI.fav(user, id) do -      render(conn, ActivityView, "activity.json", %{activity: activity, for: user}) +      conn +      |> put_view(ActivityView) +      |> render("activity.json", %{activity: activity, for: user})      end    end    def unfavorite(%{assigns: %{user: user}} = conn, %{"id" => id}) do      with {_, {:ok, id}} <- {:param_cast, Ecto.Type.cast(:integer, id)},           {:ok, activity} <- TwitterAPI.unfav(user, id) do -      render(conn, ActivityView, "activity.json", %{activity: activity, for: user}) +      conn +      |> put_view(ActivityView) +      |> render("activity.json", %{activity: activity, for: user})      end    end    def retweet(%{assigns: %{user: user}} = conn, %{"id" => id}) do      with {_, {:ok, id}} <- {:param_cast, Ecto.Type.cast(:integer, id)},           {:ok, activity} <- TwitterAPI.repeat(user, id) do -      render(conn, ActivityView, "activity.json", %{activity: activity, for: user}) +      conn +      |> put_view(ActivityView) +      |> render("activity.json", %{activity: activity, for: user})      end    end    def unretweet(%{assigns: %{user: user}} = conn, %{"id" => id}) do      with {_, {:ok, id}} <- {:param_cast, Ecto.Type.cast(:integer, id)},           {:ok, activity} <- TwitterAPI.unrepeat(user, id) do -      render(conn, ActivityView, "activity.json", %{activity: activity, for: user}) +      conn +      |> put_view(ActivityView) +      |> render("activity.json", %{activity: activity, for: user})      end    end    def register(conn, params) do      with {:ok, user} <- TwitterAPI.register_user(params) do -      render(conn, UserView, "show.json", %{user: user}) +      conn +      |> put_view(UserView) +      |> render("show.json", %{user: user})      else        {:error, errors} ->          conn @@ -339,7 +378,9 @@ defmodule Pleroma.Web.TwitterAPI.Controller do      {:ok, user} = User.update_and_set_cache(change)      CommonAPI.update(user) -    render(conn, UserView, "show.json", %{user: user, for: user}) +    conn +    |> put_view(UserView) +    |> render("show.json", %{user: user, for: user})    end    def update_banner(%{assigns: %{user: user}} = conn, params) do @@ -394,7 +435,9 @@ defmodule Pleroma.Web.TwitterAPI.Controller do            true -> followers          end -      render(conn, UserView, "index.json", %{users: followers, for: conn.assigns[:user]}) +      conn +      |> put_view(UserView) +      |> render("index.json", %{users: followers, for: conn.assigns[:user]})      else        _e -> bad_request_reply(conn, "Can't get followers")      end @@ -410,7 +453,9 @@ defmodule Pleroma.Web.TwitterAPI.Controller do            true -> friends          end -      render(conn, UserView, "index.json", %{users: friends, for: conn.assigns[:user]}) +      conn +      |> put_view(UserView) +      |> render("index.json", %{users: friends, for: conn.assigns[:user]})      else        _e -> bad_request_reply(conn, "Can't get friends")      end @@ -419,7 +464,9 @@ defmodule Pleroma.Web.TwitterAPI.Controller do    def friend_requests(conn, params) do      with {:ok, user} <- TwitterAPI.get_user(conn.assigns[:user], params),           {:ok, friend_requests} <- User.get_follow_requests(user) do -      render(conn, UserView, "index.json", %{users: friend_requests, for: conn.assigns[:user]}) +      conn +      |> put_view(UserView) +      |> render("index.json", %{users: friend_requests, for: conn.assigns[:user]})      else        _e -> bad_request_reply(conn, "Can't get friend requests")      end @@ -439,7 +486,9 @@ defmodule Pleroma.Web.TwitterAPI.Controller do               object: follow_activity.data["id"],               type: "Accept"             }) do -      render(conn, UserView, "show.json", %{user: follower, for: followed}) +      conn +      |> put_view(UserView) +      |> render("show.json", %{user: follower, for: followed})      else        e -> bad_request_reply(conn, "Can't approve user: #{inspect(e)}")      end @@ -458,7 +507,9 @@ defmodule Pleroma.Web.TwitterAPI.Controller do               object: follow_activity.data["id"],               type: "Reject"             }) do -      render(conn, UserView, "show.json", %{user: follower, for: followed}) +      conn +      |> put_view(UserView) +      |> render("show.json", %{user: follower, for: followed})      else        e -> bad_request_reply(conn, "Can't deny user: #{inspect(e)}")      end @@ -522,7 +573,10 @@ defmodule Pleroma.Web.TwitterAPI.Controller do           changeset <- Ecto.Changeset.put_embed(changeset, :info, info_cng),           {:ok, user} <- User.update_and_set_cache(changeset) do        CommonAPI.update(user) -      render(conn, UserView, "user.json", %{user: user, for: user}) + +      conn +      |> put_view(UserView) +      |> render("user.json", %{user: user, for: user})      else        error ->          Logger.debug("Can't update user: #{inspect(error)}") @@ -534,14 +588,16 @@ defmodule Pleroma.Web.TwitterAPI.Controller do      activities = TwitterAPI.search(user, params)      conn -    |> render(ActivityView, "index.json", %{activities: activities, for: user}) +    |> put_view(ActivityView) +    |> render("index.json", %{activities: activities, for: user})    end    def search_user(%{assigns: %{user: user}} = conn, %{"query" => query}) do      users = User.search(query, true)      conn -    |> render(UserView, "index.json", %{users: users, for: user}) +    |> put_view(UserView) +    |> render("index.json", %{users: users, for: user})    end    defp bad_request_reply(conn, error_message) do diff --git a/lib/pleroma/web/twitter_api/views/activity_view.ex b/lib/pleroma/web/twitter_api/views/activity_view.ex index 433c3b141..0699bf1da 100644 --- a/lib/pleroma/web/twitter_api/views/activity_view.ex +++ b/lib/pleroma/web/twitter_api/views/activity_view.ex @@ -14,6 +14,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do    alias Pleroma.HTML    import Ecto.Query +  require Logger    defp query_context_ids([]), do: [] @@ -277,6 +278,11 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do      }    end +  def render("activity.json", %{activity: unhandled_activity}) do +    Logger.warn("#{__MODULE__} unhandled activity: #{inspect(unhandled_activity)}") +    nil +  end +    def render_content(%{"type" => "Note"} = object) do      summary = object["summary"] diff --git a/lib/pleroma/web/web_finger/web_finger_controller.ex b/lib/pleroma/web/web_finger/web_finger_controller.ex index 002353166..8c60300a4 100644 --- a/lib/pleroma/web/web_finger/web_finger_controller.ex +++ b/lib/pleroma/web/web_finger/web_finger_controller.ex @@ -35,4 +35,8 @@ defmodule Pleroma.Web.WebFinger.WebFingerController do          send_resp(conn, 404, "Unsupported format")      end    end + +  def webfinger(conn, _params) do +    send_resp(conn, 400, "Bad Request") +  end  end  | 
