diff options
Diffstat (limited to 'lib')
24 files changed, 623 insertions, 214 deletions
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/application.ex b/lib/pleroma/application.ex index 8705395a4..e15991957 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -24,6 +24,7 @@ defmodule Pleroma.Application do # Start the Ecto repository supervisor(Pleroma.Repo, []), worker(Pleroma.Emoji, []), + worker(Pleroma.Captcha, []), worker( Cachex, [ diff --git a/lib/pleroma/captcha/captcha.ex b/lib/pleroma/captcha/captcha.ex new file mode 100644 index 000000000..5630f6b57 --- /dev/null +++ b/lib/pleroma/captcha/captcha.ex @@ -0,0 +1,66 @@ +defmodule Pleroma.Captcha do + use GenServer + + @ets_options [:ordered_set, :private, :named_table, {:read_concurrency, true}] + + @doc false + def start_link() do + GenServer.start_link(__MODULE__, [], name: __MODULE__) + end + + @doc false + def init(_) do + # Create a ETS table to store captchas + ets_name = Module.concat(method(), Ets) + ^ets_name = :ets.new(Module.concat(method(), Ets), @ets_options) + + # Clean up old captchas every few minutes + seconds_retained = Pleroma.Config.get!([__MODULE__, :seconds_retained]) + Process.send_after(self(), :cleanup, 1000 * seconds_retained) + + {:ok, nil} + end + + @doc """ + Ask the configured captcha service for a new captcha + """ + def new() do + GenServer.call(__MODULE__, :new) + end + + @doc """ + Ask the configured captcha service to validate the captcha + """ + def validate(token, captcha) do + GenServer.call(__MODULE__, {:validate, token, captcha}) + end + + @doc false + def handle_call(:new, _from, state) do + enabled = Pleroma.Config.get([__MODULE__, :enabled]) + + if !enabled do + {:reply, %{type: :none}, state} + else + {:reply, method().new(), state} + end + end + + @doc false + def handle_call({:validate, token, captcha}, _from, state) do + {:reply, method().validate(token, captcha), state} + end + + @doc false + def handle_info(:cleanup, state) do + :ok = method().cleanup() + + seconds_retained = Pleroma.Config.get!([__MODULE__, :seconds_retained]) + # Schedule the next clenup + Process.send_after(self(), :cleanup, 1000 * seconds_retained) + + {:noreply, state} + end + + defp method, do: Pleroma.Config.get!([__MODULE__, :method]) +end diff --git a/lib/pleroma/captcha/captcha_service.ex b/lib/pleroma/captcha/captcha_service.ex new file mode 100644 index 000000000..8d0b76f86 --- /dev/null +++ b/lib/pleroma/captcha/captcha_service.ex @@ -0,0 +1,28 @@ +defmodule Pleroma.Captcha.Service do + @doc """ + Request new captcha from a captcha service. + + Returns: + + Service-specific data for using the newly created captcha + """ + @callback new() :: map + + @doc """ + Validated the provided captcha solution. + + Arguments: + * `token` the captcha is associated with + * `captcha` solution of the captcha to validate + + Returns: + + `true` if captcha is valid, `false` if not + """ + @callback validate(token :: String.t(), captcha :: String.t()) :: boolean + + @doc """ + This function is called periodically to clean up old captchas + """ + @callback cleanup() :: :ok +end diff --git a/lib/pleroma/captcha/kocaptcha.ex b/lib/pleroma/captcha/kocaptcha.ex new file mode 100644 index 000000000..51900d123 --- /dev/null +++ b/lib/pleroma/captcha/kocaptcha.ex @@ -0,0 +1,67 @@ +defmodule Pleroma.Captcha.Kocaptcha do + alias Calendar.DateTime + + alias Pleroma.Captcha.Service + @behaviour Service + + @ets __MODULE__.Ets + + @impl Service + def new() do + endpoint = Pleroma.Config.get!([__MODULE__, :endpoint]) + + case Tesla.get(endpoint <> "/new") do + {:error, _} -> + %{error: "Kocaptcha service unavailable"} + + {:ok, res} -> + json_resp = Poison.decode!(res.body) + + token = json_resp["token"] + + true = + :ets.insert( + @ets, + {token, json_resp["md5"], DateTime.now_utc() |> DateTime.Format.unix()} + ) + + %{type: :kocaptcha, token: token, url: endpoint <> json_resp["url"]} + end + end + + @impl Service + def validate(token, captcha) do + with false <- is_nil(captcha), + [{^token, saved_md5, _}] <- :ets.lookup(@ets, token), + true <- :crypto.hash(:md5, captcha) |> Base.encode16() == String.upcase(saved_md5) do + # Clear the saved value + :ets.delete(@ets, token) + + true + else + _ -> false + end + end + + @impl Service + def cleanup() do + seconds_retained = Pleroma.Config.get!([Pleroma.Captcha, :seconds_retained]) + # If the time in ETS is less than current_time - seconds_retained, then the time has + # already passed + delete_after = + DateTime.subtract!(DateTime.now_utc(), seconds_retained) |> DateTime.Format.unix() + + :ets.select_delete( + @ets, + [ + { + {:_, :_, :"$1"}, + [{:<, :"$1", {:const, delete_after}}], + [true] + } + ] + ) + + :ok + end +end 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/plugs/instance_static.ex b/lib/pleroma/plugs/instance_static.ex new file mode 100644 index 000000000..46ee77e11 --- /dev/null +++ b/lib/pleroma/plugs/instance_static.ex @@ -0,0 +1,54 @@ +defmodule Pleroma.Plugs.InstanceStatic do + @moduledoc """ + This is a shim to call `Plug.Static` but with runtime `from` configuration. + + Mountpoints are defined directly in the module to avoid calling the configuration for every request including non-static ones. + """ + @behaviour Plug + + def file_path(path) do + instance_path = + Path.join(Pleroma.Config.get([:instance, :static_dir], "instance/static/"), path) + + if File.exists?(instance_path) do + instance_path + else + Path.join(Application.app_dir(:pleroma, "priv/static/"), path) + end + end + + @only ~w(index.html static emoji packs sounds images instance favicon.png) + + def init(opts) do + opts + |> Keyword.put(:from, "__unconfigured_instance_static_plug") + |> Keyword.put(:at, "/__unconfigured_instance_static_plug") + |> Plug.Static.init() + end + + for only <- @only do + at = Plug.Router.Utils.split("/") + + def call(conn = %{request_path: "/" <> unquote(only) <> _}, opts) do + call_static( + conn, + opts, + unquote(at), + Pleroma.Config.get([:instance, :static_dir], "instance/static") + ) + end + end + + def call(conn, _) do + conn + end + + defp call_static(conn, opts, at, from) do + opts = + opts + |> Map.put(:from, from) + |> Map.put(:at, at) + + Plug.Static.call(conn, opts) + 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..d79f61b2e 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 @@ -14,6 +12,10 @@ defmodule Pleroma.Web.Endpoint do plug(Pleroma.Plugs.UploadedMedia) + # InstanceStatic needs to be before Plug.Static to be able to override shipped-static files + # If you're adding new paths to `only:` you'll need to configure them in InstanceStatic as well + plug(Pleroma.Plugs.InstanceStatic, at: "/") + plug( Plug.Static, at: "/", 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/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex index 9dfcf0f95..6005eadb2 100644 --- a/lib/pleroma/web/ostatus/ostatus_controller.ex +++ b/lib/pleroma/web/ostatus/ostatus_controller.ex @@ -136,7 +136,7 @@ defmodule Pleroma.Web.OStatus.OStatusController do "html" -> conn |> put_resp_content_type("text/html") - |> send_file(200, Application.app_dir(:pleroma, "priv/static/index.html")) + |> send_file(200, Pleroma.Plugs.InstanceStatic.file_path("index.html")) _ -> represent_activity(conn, format, activity, user) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index daff3362c..dd1985d6e 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -99,6 +99,7 @@ defmodule Pleroma.Web.Router do get("/password_reset/:token", UtilController, :show_password_reset) post("/password_reset", UtilController, :password_reset) get("/emoji", UtilController, :emoji) + get("/captcha", UtilController, :captcha) end scope "/api/pleroma/admin", Pleroma.Web.AdminAPI do @@ -458,7 +459,7 @@ defmodule Fallback.RedirectController do def redirector(conn, _params) do conn |> put_resp_content_type("text/html") - |> send_file(200, Application.app_dir(:pleroma, "priv/static/index.html")) + |> send_file(200, Pleroma.Plugs.InstanceStatic.file_path("index.html")) end def registration_page(conn, params) do 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/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 2f2b69623..38653f0b8 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -284,4 +284,8 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do json(conn, %{error: msg}) end end + + def captcha(conn, _params) do + json(conn, Pleroma.Captcha.new()) + end end diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index 1e764f24a..90b8345c5 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -132,38 +132,55 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do bio: User.parse_bio(params["bio"]), email: params["email"], password: params["password"], - password_confirmation: params["confirm"] + password_confirmation: params["confirm"], + captcha_solution: params["captcha_solution"], + captcha_token: params["captcha_token"] } - registrations_open = Pleroma.Config.get([:instance, :registrations_open]) - - # no need to query DB if registration is open - token = - unless registrations_open || is_nil(tokenString) do - Repo.get_by(UserInviteToken, %{token: tokenString}) + captcha_enabled = Pleroma.Config.get([Pleroma.Captcha, :enabled]) + # true if captcha is disabled or enabled and valid, false otherwise + captcha_ok = + if !captcha_enabled do + true + else + Pleroma.Captcha.validate(params[:captcha_token], params[:captcha_solution]) end - cond do - registrations_open || (!is_nil(token) && !token.used) -> - changeset = User.register_changeset(%User{info: %{}}, params) - - with {:ok, user} <- Repo.insert(changeset) do - !registrations_open && UserInviteToken.mark_as_used(token.token) - {:ok, user} - else - {:error, changeset} -> - errors = - Ecto.Changeset.traverse_errors(changeset, fn {msg, _opts} -> msg end) - |> Jason.encode!() + # Captcha invalid + if not captcha_ok do + # I have no idea how this error handling works + {:error, %{error: Jason.encode!(%{captcha: ["Invalid CAPTCHA"]})}} + else + registrations_open = Pleroma.Config.get([:instance, :registrations_open]) - {:error, %{error: errors}} + # no need to query DB if registration is open + token = + unless registrations_open || is_nil(tokenString) do + Repo.get_by(UserInviteToken, %{token: tokenString}) end - !registrations_open && is_nil(token) -> - {:error, "Invalid token"} + cond do + registrations_open || (!is_nil(token) && !token.used) -> + changeset = User.register_changeset(%User{info: %{}}, params) - !registrations_open && token.used -> - {:error, "Expired token"} + with {:ok, user} <- Repo.insert(changeset) do + !registrations_open && UserInviteToken.mark_as_used(token.token) + {:ok, user} + else + {:error, changeset} -> + errors = + Ecto.Changeset.traverse_errors(changeset, fn {msg, _opts} -> msg end) + |> Jason.encode!() + + {:error, %{error: errors}} + end + + !registrations_open && is_nil(token) -> + {:error, "Invalid token"} + + !registrations_open && token.used -> + {:error, "Expired token"} + end end 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 0699bf1da..91d086740 100644 --- a/lib/pleroma/web/twitter_api/views/activity_view.ex +++ b/lib/pleroma/web/twitter_api/views/activity_view.ex @@ -244,6 +244,11 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do |> HTML.filter_tags(User.html_filter_policy(opts[:for])) |> Formatter.emojify(object["emoji"]) + text = + content + |> String.replace(~r/<br\s?\/?>/, "\n") + |> HTML.strip_tags() + reply_parent = Activity.get_in_reply_to_activity(activity) reply_user = reply_parent && User.get_cached_by_ap_id(reply_parent.actor) @@ -253,7 +258,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do "uri" => activity.data["object"]["id"], "user" => UserView.render("show.json", %{user: user, for: opts[:for]}), "statusnet_html" => html, - "text" => HTML.strip_tags(content), + "text" => text, "is_local" => activity.local, "is_post_verb" => true, "created_at" => created_at, diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex index b3459af9a..8a88d72b1 100644 --- a/lib/pleroma/web/twitter_api/views/user_view.ex +++ b/lib/pleroma/web/twitter_api/views/user_view.ex @@ -86,7 +86,7 @@ defmodule Pleroma.Web.TwitterAPI.UserView do } if assigns[:token] do - Map.put(data, "token", assigns[:token]) + Map.put(data, "token", token_string(assigns[:token])) else data end @@ -111,4 +111,7 @@ defmodule Pleroma.Web.TwitterAPI.UserView do defp image_url(%{"url" => [%{"href" => href} | _]}), do: href defp image_url(_), do: nil + + defp token_string(%Pleroma.Web.OAuth.Token{token: token_str}), do: token_str + defp token_string(token), do: token end 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 |