aboutsummaryrefslogtreecommitdiff
path: root/lib/pleroma/web
diff options
context:
space:
mode:
authorEgor Kislitsyn <egor@kislitsyn.com>2019-05-07 16:51:11 +0700
committerEgor Kislitsyn <egor@kislitsyn.com>2019-05-07 16:51:11 +0700
commit1557b99beb3b406572ef2d3baaabed1c9baeca1c (patch)
tree34041b8526ecfa38fcb0b471718de0b3b71aa8c4 /lib/pleroma/web
parentc157e27a000a12dc8f660c056744a6611beb01b1 (diff)
parent6518644db1d31f2b30b95fa0899b3751bc330d56 (diff)
downloadpleroma-1557b99beb3b406572ef2d3baaabed1c9baeca1c.tar.gz
Merge remote-tracking branch 'pleroma/develop' into feature/disable-account
Diffstat (limited to 'lib/pleroma/web')
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub.ex3
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub_controller.ex2
-rw-r--r--lib/pleroma/web/activity_pub/relay.ex4
-rw-r--r--lib/pleroma/web/activity_pub/transmogrifier.ex74
-rw-r--r--lib/pleroma/web/activity_pub/views/user_view.ex7
-rw-r--r--lib/pleroma/web/auth/authenticator.ex26
-rw-r--r--lib/pleroma/web/auth/ldap_authenticator.ex39
-rw-r--r--lib/pleroma/web/auth/pleroma_authenticator.ex15
-rw-r--r--lib/pleroma/web/common_api/common_api.ex19
-rw-r--r--lib/pleroma/web/common_api/utils.ex12
-rw-r--r--lib/pleroma/web/mastodon_api/mastodon_api_controller.ex89
-rw-r--r--lib/pleroma/web/mastodon_api/views/account_view.ex58
-rw-r--r--lib/pleroma/web/mastodon_api/views/status_view.ex5
-rw-r--r--lib/pleroma/web/media_proxy/media_proxy.ex50
-rw-r--r--lib/pleroma/web/oauth/app.ex1
-rw-r--r--lib/pleroma/web/oauth/authorization.ex8
-rw-r--r--lib/pleroma/web/oauth/oauth_controller.ex159
-rw-r--r--lib/pleroma/web/oauth/token.ex81
-rw-r--r--lib/pleroma/web/oauth/token/strategy/refresh_token.ex54
-rw-r--r--lib/pleroma/web/oauth/token/strategy/revoke.ex22
-rw-r--r--lib/pleroma/web/oauth/token/utils.ex30
-rw-r--r--lib/pleroma/web/push/impl.ex25
-rw-r--r--lib/pleroma/web/twitter_api/controllers/util_controller.ex2
-rw-r--r--lib/pleroma/web/twitter_api/twitter_api.ex2
-rw-r--r--lib/pleroma/web/twitter_api/twitter_api_controller.ex18
-rw-r--r--lib/pleroma/web/twitter_api/views/user_view.ex124
26 files changed, 651 insertions, 278 deletions
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 6bf54d1cc..d06bc64ea 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -168,7 +168,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
public = "https://www.w3.org/ns/activitystreams#Public"
if activity.data["type"] in ["Create", "Announce", "Delete"] do
- object = Object.normalize(activity)
Pleroma.Web.Streamer.stream("user", activity)
Pleroma.Web.Streamer.stream("list", activity)
@@ -180,6 +179,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
if activity.data["type"] in ["Create"] do
+ object = Object.normalize(activity)
+
object.data
|> Map.get("tag", [])
|> Enum.filter(fn tag -> is_bitstring(tag) end)
diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
index 0b80566bf..c967ab7a9 100644
--- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
@@ -155,7 +155,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
def inbox(%{assigns: %{valid_signature: true}} = conn, %{"nickname" => nickname} = params) do
with %User{} = recipient <- User.get_cached_by_nickname(nickname),
- %User{} = actor <- User.get_or_fetch_by_ap_id(params["actor"]),
+ {:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(params["actor"]),
true <- Utils.recipient_in_message(recipient, actor, params),
params <- Utils.maybe_splice_recipient(recipient.ap_id, params) do
Federator.incoming_ap_doc(params)
diff --git a/lib/pleroma/web/activity_pub/relay.ex b/lib/pleroma/web/activity_pub/relay.ex
index a7a20ca37..93808517b 100644
--- a/lib/pleroma/web/activity_pub/relay.ex
+++ b/lib/pleroma/web/activity_pub/relay.ex
@@ -15,7 +15,7 @@ defmodule Pleroma.Web.ActivityPub.Relay do
def follow(target_instance) do
with %User{} = local_user <- get_actor(),
- %User{} = target_user <- User.get_or_fetch_by_ap_id(target_instance),
+ {:ok, %User{} = target_user} <- User.get_or_fetch_by_ap_id(target_instance),
{:ok, activity} <- ActivityPub.follow(local_user, target_user) do
Logger.info("relay: followed instance: #{target_instance}; id=#{activity.data["id"]}")
{:ok, activity}
@@ -28,7 +28,7 @@ defmodule Pleroma.Web.ActivityPub.Relay do
def unfollow(target_instance) do
with %User{} = local_user <- get_actor(),
- %User{} = target_user <- User.get_or_fetch_by_ap_id(target_instance),
+ {:ok, %User{} = target_user} <- User.get_or_fetch_by_ap_id(target_instance),
{:ok, activity} <- ActivityPub.unfollow(local_user, target_user) do
Logger.info("relay: unfollowed instance: #{target_instance}: id=#{activity.data["id"]}")
{:ok, activity}
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index 52666a409..508f3532f 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -126,7 +126,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
def fix_implicit_addressing(object, _), do: object
def fix_addressing(object) do
- %User{} = user = User.get_or_fetch_by_ap_id(object["actor"])
+ {:ok, %User{} = user} = User.get_or_fetch_by_ap_id(object["actor"])
followers_collection = User.ap_followers(user)
object
@@ -407,7 +407,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|> fix_addressing
with nil <- Activity.get_create_by_object_ap_id(object["id"]),
- %User{} = user <- User.get_or_fetch_by_ap_id(data["actor"]) do
+ {:ok, %User{} = user} <- User.get_or_fetch_by_ap_id(data["actor"]) do
object = fix_object(data["object"])
params = %{
@@ -436,22 +436,48 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
%{"type" => "Follow", "object" => followed, "actor" => follower, "id" => id} = data
) do
with %User{local: true} = followed <- User.get_cached_by_ap_id(followed),
- %User{} = follower <- User.get_or_fetch_by_ap_id(follower),
+ {:ok, %User{} = follower} <- User.get_or_fetch_by_ap_id(follower),
{:ok, activity} <- ActivityPub.follow(follower, followed, id, false) do
- if not User.locked?(followed) do
+ with deny_follow_blocked <- Pleroma.Config.get([:user, :deny_follow_blocked]),
+ {:user_blocked, false} <-
+ {:user_blocked, User.blocks?(followed, follower) && deny_follow_blocked},
+ {:user_locked, false} <- {:user_locked, User.locked?(followed)},
+ {:follow, {:ok, follower}} <- {:follow, User.follow(follower, followed)} do
ActivityPub.accept(%{
to: [follower.ap_id],
actor: followed,
object: data,
local: true
})
-
- User.follow(follower, followed)
+ else
+ {:user_blocked, true} ->
+ {:ok, _} = Utils.update_follow_state(activity, "reject")
+
+ ActivityPub.reject(%{
+ to: [follower.ap_id],
+ actor: followed,
+ object: data,
+ local: true
+ })
+
+ {:follow, {:error, _}} ->
+ {:ok, _} = Utils.update_follow_state(activity, "reject")
+
+ ActivityPub.reject(%{
+ to: [follower.ap_id],
+ actor: followed,
+ object: data,
+ local: true
+ })
+
+ {:user_locked, true} ->
+ :noop
end
{:ok, activity}
else
- _e -> :error
+ _e ->
+ :error
end
end
@@ -459,7 +485,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
%{"type" => "Accept", "object" => follow_object, "actor" => _actor, "id" => _id} = data
) do
with actor <- Containment.get_actor(data),
- %User{} = followed <- User.get_or_fetch_by_ap_id(actor),
+ {:ok, %User{} = followed} <- User.get_or_fetch_by_ap_id(actor),
{:ok, follow_activity} <- get_follow_activity(follow_object, followed),
{:ok, follow_activity} <- Utils.update_follow_state(follow_activity, "accept"),
%User{local: true} = follower <- User.get_cached_by_ap_id(follow_activity.data["actor"]),
@@ -485,7 +511,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
%{"type" => "Reject", "object" => follow_object, "actor" => _actor, "id" => _id} = data
) do
with actor <- Containment.get_actor(data),
- %User{} = followed <- User.get_or_fetch_by_ap_id(actor),
+ {:ok, %User{} = followed} <- User.get_or_fetch_by_ap_id(actor),
{:ok, follow_activity} <- get_follow_activity(follow_object, followed),
{:ok, follow_activity} <- Utils.update_follow_state(follow_activity, "reject"),
%User{local: true} = follower <- User.get_cached_by_ap_id(follow_activity.data["actor"]),
@@ -509,7 +535,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
%{"type" => "Like", "object" => object_id, "actor" => _actor, "id" => id} = data
) do
with actor <- Containment.get_actor(data),
- %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
+ {:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(actor),
{:ok, object} <- get_obj_helper(object_id),
{:ok, activity, _object} <- ActivityPub.like(actor, object, id, false) do
{:ok, activity}
@@ -522,7 +548,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
%{"type" => "Announce", "object" => object_id, "actor" => _actor, "id" => id} = data
) do
with actor <- Containment.get_actor(data),
- %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
+ {:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(actor),
{:ok, object} <- get_obj_helper(object_id),
public <- Visibility.is_public?(data),
{:ok, activity, _object} <- ActivityPub.announce(actor, object, id, false, public) do
@@ -577,7 +603,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
object_id = Utils.get_ap_id(object_id)
with actor <- Containment.get_actor(data),
- %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
+ {:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(actor),
{:ok, object} <- get_obj_helper(object_id),
:ok <- Containment.contain_origin(actor.ap_id, object.data),
{:ok, activity} <- ActivityPub.delete(object, false) do
@@ -596,7 +622,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
} = data
) do
with actor <- Containment.get_actor(data),
- %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
+ {:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(actor),
{:ok, object} <- get_obj_helper(object_id),
{:ok, activity, _} <- ActivityPub.unannounce(actor, object, id, false) do
{:ok, activity}
@@ -614,7 +640,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
} = _data
) do
with %User{local: true} = followed <- User.get_cached_by_ap_id(followed),
- %User{} = follower <- User.get_or_fetch_by_ap_id(follower),
+ {:ok, %User{} = follower} <- User.get_or_fetch_by_ap_id(follower),
{:ok, activity} <- ActivityPub.unfollow(follower, followed, id, false) do
User.unfollow(follower, followed)
{:ok, activity}
@@ -633,7 +659,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
) do
with true <- Pleroma.Config.get([:activitypub, :accept_blocks]),
%User{local: true} = blocked <- User.get_cached_by_ap_id(blocked),
- %User{} = blocker <- User.get_or_fetch_by_ap_id(blocker),
+ {:ok, %User{} = blocker} <- User.get_or_fetch_by_ap_id(blocker),
{:ok, activity} <- ActivityPub.unblock(blocker, blocked, id, false) do
User.unblock(blocker, blocked)
{:ok, activity}
@@ -647,7 +673,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
) do
with true <- Pleroma.Config.get([:activitypub, :accept_blocks]),
%User{local: true} = blocked = User.get_cached_by_ap_id(blocked),
- %User{} = blocker = User.get_or_fetch_by_ap_id(blocker),
+ {:ok, %User{} = blocker} = User.get_or_fetch_by_ap_id(blocker),
{:ok, activity} <- ActivityPub.block(blocker, blocked, id, false) do
User.unfollow(blocker, blocked)
User.block(blocker, blocked)
@@ -666,7 +692,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
} = data
) do
with actor <- Containment.get_actor(data),
- %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
+ {:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(actor),
{:ok, object} <- get_obj_helper(object_id),
{:ok, activity, _, _} <- ActivityPub.unlike(actor, object, id, false) do
{:ok, activity}
@@ -830,10 +856,16 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|> Map.put("tag", tags ++ mentions)
end
+ def add_emoji_tags(%User{info: %{"emoji" => _emoji} = user_info} = object) do
+ user_info = add_emoji_tags(user_info)
+
+ object
+ |> Map.put(:info, user_info)
+ end
+
# TODO: we should probably send mtime instead of unix epoch time for updated
- def add_emoji_tags(object) do
+ def add_emoji_tags(%{"emoji" => emoji} = object) do
tags = object["tag"] || []
- emoji = object["emoji"] || []
out =
emoji
@@ -851,6 +883,10 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|> Map.put("tag", tags ++ out)
end
+ def add_emoji_tags(object) do
+ object
+ end
+
def set_conversation(object) do
Map.put(object, "conversation", object["context"])
end
diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex
index 5926a3294..1254fdf6c 100644
--- a/lib/pleroma/web/activity_pub/views/user_view.ex
+++ b/lib/pleroma/web/activity_pub/views/user_view.ex
@@ -69,6 +69,11 @@ defmodule Pleroma.Web.ActivityPub.UserView do
endpoints = render("endpoints.json", %{user: user})
+ user_tags =
+ user
+ |> Transmogrifier.add_emoji_tags()
+ |> Map.get("tag", [])
+
%{
"id" => user.ap_id,
"type" => "Person",
@@ -87,7 +92,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
"publicKeyPem" => public_key
},
"endpoints" => endpoints,
- "tag" => user.info.source_data["tag"] || []
+ "tag" => (user.info.source_data["tag"] || []) ++ user_tags
}
|> Map.merge(maybe_make_image(&User.avatar_url/2, "icon", user))
|> Map.merge(maybe_make_image(&User.banner_url/2, "image", user))
diff --git a/lib/pleroma/web/auth/authenticator.ex b/lib/pleroma/web/auth/authenticator.ex
index b02f595dc..d4e0ffa80 100644
--- a/lib/pleroma/web/auth/authenticator.ex
+++ b/lib/pleroma/web/auth/authenticator.ex
@@ -42,4 +42,30 @@ defmodule Pleroma.Web.Auth.Authenticator do
implementation().oauth_consumer_template() ||
Pleroma.Config.get([:auth, :oauth_consumer_template], "consumer.html")
end
+
+ @doc "Gets user by nickname or email for auth."
+ @spec fetch_user(String.t()) :: User.t() | nil
+ def fetch_user(name) do
+ User.get_by_nickname_or_email(name)
+ end
+
+ # Gets name and password from conn
+ #
+ @spec fetch_credentials(Plug.Conn.t() | map()) ::
+ {:ok, {name :: any, password :: any}} | {:error, :invalid_credentials}
+ def fetch_credentials(%Plug.Conn{params: params} = _),
+ do: fetch_credentials(params)
+
+ def fetch_credentials(params) do
+ case params do
+ %{"authorization" => %{"name" => name, "password" => password}} ->
+ {:ok, {name, password}}
+
+ %{"grant_type" => "password", "username" => name, "password" => password} ->
+ {:ok, {name, password}}
+
+ _ ->
+ {:error, :invalid_credentials}
+ end
+ end
end
diff --git a/lib/pleroma/web/auth/ldap_authenticator.ex b/lib/pleroma/web/auth/ldap_authenticator.ex
index 363c99597..177c05636 100644
--- a/lib/pleroma/web/auth/ldap_authenticator.ex
+++ b/lib/pleroma/web/auth/ldap_authenticator.ex
@@ -7,6 +7,9 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do
require Logger
+ import Pleroma.Web.Auth.Authenticator,
+ only: [fetch_credentials: 1, fetch_user: 1]
+
@behaviour Pleroma.Web.Auth.Authenticator
@base Pleroma.Web.Auth.PleromaAuthenticator
@@ -20,30 +23,20 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do
defdelegate oauth_consumer_template, to: @base
def get_user(%Plug.Conn{} = conn) do
- if Pleroma.Config.get([:ldap, :enabled]) do
- {name, password} =
- case conn.params do
- %{"authorization" => %{"name" => name, "password" => password}} ->
- {name, password}
-
- %{"grant_type" => "password", "username" => name, "password" => password} ->
- {name, password}
- end
-
- case ldap_user(name, password) do
- %User{} = user ->
- {:ok, user}
+ with {:ldap, true} <- {:ldap, Pleroma.Config.get([:ldap, :enabled])},
+ {:ok, {name, password}} <- fetch_credentials(conn),
+ %User{} = user <- ldap_user(name, password) do
+ {:ok, user}
+ else
+ {:error, {:ldap_connection_error, _}} ->
+ # When LDAP is unavailable, try default authenticator
+ @base.get_user(conn)
- {:error, {:ldap_connection_error, _}} ->
- # When LDAP is unavailable, try default authenticator
- @base.get_user(conn)
+ {:ldap, _} ->
+ @base.get_user(conn)
- error ->
- error
- end
- else
- # Fall back to default authenticator
- @base.get_user(conn)
+ error ->
+ error
end
end
@@ -94,7 +87,7 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do
case :eldap.simple_bind(connection, "#{uid}=#{name},#{base}", password) do
:ok ->
- case User.get_by_nickname_or_email(name) do
+ case fetch_user(name) do
%User{} = user ->
user
diff --git a/lib/pleroma/web/auth/pleroma_authenticator.ex b/lib/pleroma/web/auth/pleroma_authenticator.ex
index d647f1e05..dd79cdcf7 100644
--- a/lib/pleroma/web/auth/pleroma_authenticator.ex
+++ b/lib/pleroma/web/auth/pleroma_authenticator.ex
@@ -8,19 +8,14 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do
alias Pleroma.Repo
alias Pleroma.User
+ import Pleroma.Web.Auth.Authenticator,
+ only: [fetch_credentials: 1, fetch_user: 1]
+
@behaviour Pleroma.Web.Auth.Authenticator
def get_user(%Plug.Conn{} = conn) do
- {name, password} =
- case conn.params do
- %{"authorization" => %{"name" => name, "password" => password}} ->
- {name, password}
-
- %{"grant_type" => "password", "username" => name, "password" => password} ->
- {name, password}
- end
-
- with {_, %User{} = user} <- {:user, User.get_by_nickname_or_email(name)},
+ with {:ok, {name, password}} <- fetch_credentials(conn),
+ {_, %User{} = user} <- {:user, fetch_user(name)},
{_, true} <- {:checkpw, Pbkdf2.checkpw(password, user.password_hash)} do
{:ok, user}
else
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index cfbc5dc10..b53869c75 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -4,6 +4,7 @@
defmodule Pleroma.Web.CommonAPI do
alias Pleroma.Activity
+ alias Pleroma.Bookmark
alias Pleroma.Formatter
alias Pleroma.Object
alias Pleroma.ThreadMute
@@ -150,8 +151,8 @@ defmodule Pleroma.Web.CommonAPI do
),
{to, cc} <- to_for_user_and_mentions(user, mentions, in_reply_to, visibility),
context <- make_context(in_reply_to),
- cw <- data["spoiler_text"],
- full_payload <- String.trim(status <> (data["spoiler_text"] || "")),
+ cw <- data["spoiler_text"] || "",
+ full_payload <- String.trim(status <> cw),
length when length in 1..limit <- String.length(full_payload),
object <-
make_note_data(
@@ -169,10 +170,7 @@ defmodule Pleroma.Web.CommonAPI do
Map.put(
object,
"emoji",
- (Formatter.get_emoji(status) ++ Formatter.get_emoji(data["spoiler_text"]))
- |> Enum.reduce(%{}, fn {name, file, _}, acc ->
- Map.put(acc, name, "#{Pleroma.Web.Endpoint.static_url()}#{file}")
- end)
+ Formatter.get_emoji_map(full_payload)
) do
res =
ActivityPub.create(
@@ -282,6 +280,15 @@ defmodule Pleroma.Web.CommonAPI do
end
end
+ def bookmarked?(user, activity) do
+ with %Bookmark{} <- Bookmark.get(user.id, activity.id) do
+ true
+ else
+ _ ->
+ false
+ end
+ end
+
def report(user, data) do
with {:account_id, %{"account_id" => account_id}} <- {:account_id, data},
{:account, %User{} = account} <- {:account, User.get_cached_by_id(account_id)},
diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex
index 887f878c4..1dfe50b40 100644
--- a/lib/pleroma/web/common_api/utils.ex
+++ b/lib/pleroma/web/common_api/utils.ex
@@ -183,6 +183,18 @@ defmodule Pleroma.Web.CommonAPI.Utils do
end
@doc """
+ Formatting text as BBCode.
+ """
+ def format_input(text, "text/bbcode", options) do
+ text
+ |> String.replace(~r/\r/, "")
+ |> Formatter.html_escape("text/plain")
+ |> BBCode.to_html()
+ |> (fn {:ok, html} -> html end).()
+ |> Formatter.linkify(options)
+ end
+
+ @doc """
Formatting text to html.
"""
def format_input(text, "text/html", options) do
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index 0ba8d9eea..b099199af 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -6,8 +6,10 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
use Pleroma.Web, :controller
alias Ecto.Changeset
alias Pleroma.Activity
+ alias Pleroma.Bookmark
alias Pleroma.Config
alias Pleroma.Filter
+ alias Pleroma.Formatter
alias Pleroma.Notification
alias Pleroma.Object
alias Pleroma.Object.Fetcher
@@ -35,7 +37,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
alias Pleroma.Web.OAuth.Authorization
alias Pleroma.Web.OAuth.Token
- import Pleroma.Web.ControllerHelper, only: [oauth_scopes: 2]
+ alias Pleroma.Web.ControllerHelper
import Ecto.Query
require Logger
@@ -46,7 +48,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
action_fallback(:errors)
def create_app(conn, params) do
- scopes = oauth_scopes(params, ["read"])
+ scopes = ControllerHelper.oauth_scopes(params, ["read"])
app_attrs =
params
@@ -85,7 +87,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
user_params =
%{}
|> add_if_present(params, "display_name", :name)
- |> add_if_present(params, "note", :bio, fn value -> {:ok, User.parse_bio(value)} end)
+ |> add_if_present(params, "note", :bio, fn value -> {:ok, User.parse_bio(value, user)} end)
|> add_if_present(params, "avatar", :avatar, fn value ->
with %Plug.Upload{} <- value,
{:ok, object} <- ActivityPub.upload(value, type: :avatar) do
@@ -95,9 +97,20 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
end)
+ emojis_text = (user_params["display_name"] || "") <> (user_params["note"] || "")
+
+ user_info_emojis =
+ ((user.info.emoji || []) ++ Formatter.get_emoji_map(emojis_text))
+ |> Enum.dedup()
+
info_params =
- %{}
- |> add_if_present(params, "locked", :locked, fn value -> {:ok, value == "true"} end)
+ [:no_rich_text, :locked, :hide_followers, :hide_follows, :hide_favorites, :show_role]
+ |> Enum.reduce(%{}, fn key, acc ->
+ add_if_present(acc, params, to_string(key), key, fn value ->
+ {:ok, ControllerHelper.truthy_param?(value)}
+ end)
+ end)
+ |> add_if_present(params, "default_scope", :default_scope)
|> add_if_present(params, "header", :banner, fn value ->
with %Plug.Upload{} <- value,
{:ok, object} <- ActivityPub.upload(value, type: :banner) do
@@ -106,8 +119,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
_ -> :error
end
end)
+ |> Map.put(:emoji, user_info_emojis)
- info_cng = User.Info.mastodon_profile_update(user.info, info_params)
+ info_cng = User.Info.profile_update(user.info, info_params)
with changeset <- User.update_changeset(user, user_params),
changeset <- Ecto.Changeset.put_embed(changeset, :info, info_cng),
@@ -279,6 +293,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|> ActivityPub.contain_timeline(user)
|> Enum.reverse()
+ user = Repo.preload(user, bookmarks: :activity)
+
conn
|> add_link_headers(:home_timeline, activities)
|> put_view(StatusView)
@@ -297,6 +313,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|> ActivityPub.fetch_public_activities()
|> Enum.reverse()
+ user = Repo.preload(user, bookmarks: :activity)
+
conn
|> add_link_headers(:public_timeline, activities, false, %{"local" => local_only})
|> put_view(StatusView)
@@ -304,7 +322,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def user_statuses(%{assigns: %{user: reading_user}} = conn, params) do
- with %User{} = user <- User.get_cached_by_id(params["id"]) do
+ with %User{} = user <- User.get_cached_by_id(params["id"]),
+ reading_user <- Repo.preload(reading_user, :bookmarks) do
activities = ActivityPub.fetch_user_activities(user, reading_user, params)
conn
@@ -331,6 +350,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|> ActivityPub.fetch_activities_query(params)
|> Pagination.fetch_paginated(params)
+ user = Repo.preload(user, bookmarks: :activity)
+
conn
|> add_link_headers(:dm_timeline, activities)
|> put_view(StatusView)
@@ -340,6 +361,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
def get_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
with %Activity{} = activity <- Activity.get_by_id_with_object(id),
true <- Visibility.visible_for_user?(activity, user) do
+ user = Repo.preload(user, bookmarks: :activity)
+
conn
|> put_view(StatusView)
|> try_render("status.json", %{activity: activity, for: user})
@@ -489,6 +512,8 @@ 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),
%Activity{} = announce <- Activity.normalize(announce.data) do
+ user = Repo.preload(user, bookmarks: :activity)
+
conn
|> put_view(StatusView)
|> try_render("status.json", %{activity: announce, for: user, as: :activity})
@@ -498,6 +523,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
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_by_object_ap_id_with_object(id) do
+ user = Repo.preload(user, bookmarks: :activity)
+
conn
|> put_view(StatusView)
|> try_render("status.json", %{activity: activity, for: user, as: :activity})
@@ -545,10 +572,11 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
def bookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
with %Activity{} = activity <- Activity.get_by_id_with_object(id),
- %Object{} = object <- Object.normalize(activity),
%User{} = user <- User.get_cached_by_nickname(user.nickname),
true <- Visibility.visible_for_user?(activity, user),
- {:ok, user} <- User.bookmark(user, object.data["id"]) do
+ {:ok, _bookmark} <- Bookmark.create(user.id, activity.id) do
+ user = Repo.preload(user, bookmarks: :activity)
+
conn
|> put_view(StatusView)
|> try_render("status.json", %{activity: activity, for: user, as: :activity})
@@ -557,10 +585,11 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
def unbookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
with %Activity{} = activity <- Activity.get_by_id_with_object(id),
- %Object{} = object <- Object.normalize(activity),
%User{} = user <- User.get_cached_by_nickname(user.nickname),
true <- Visibility.visible_for_user?(activity, user),
- {:ok, user} <- User.unbookmark(user, object.data["id"]) do
+ {:ok, _bookmark} <- Bookmark.destroy(user.id, activity.id) do
+ user = Repo.preload(user, bookmarks: :activity)
+
conn
|> put_view(StatusView)
|> try_render("status.json", %{activity: activity, for: user, as: :activity})
@@ -683,7 +712,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
end
- def favourited_by(conn, %{"id" => id}) do
+ def favourited_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do
with %Activity{data: %{"object" => object}} <- Repo.get(Activity, id),
%Object{data: %{"likes" => likes}} <- Object.normalize(object) do
q = from(u in User, where: u.ap_id in ^likes)
@@ -691,13 +720,13 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
conn
|> put_view(AccountView)
- |> render(AccountView, "accounts.json", %{users: users, as: :user})
+ |> render(AccountView, "accounts.json", %{for: user, users: users, as: :user})
else
_ -> json(conn, [])
end
end
- def reblogged_by(conn, %{"id" => id}) do
+ def reblogged_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do
with %Activity{data: %{"object" => object}} <- Repo.get(Activity, id),
%Object{data: %{"announcements" => announces}} <- Object.normalize(object) do
q = from(u in User, where: u.ap_id in ^announces)
@@ -705,7 +734,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
conn
|> put_view(AccountView)
- |> render("accounts.json", %{users: users, as: :user})
+ |> render("accounts.json", %{for: user, users: users, as: :user})
else
_ -> json(conn, [])
end
@@ -762,7 +791,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
conn
|> add_link_headers(:followers, followers, user)
|> put_view(AccountView)
- |> render("accounts.json", %{users: followers, as: :user})
+ |> render("accounts.json", %{for: for_user, users: followers, as: :user})
end
end
@@ -779,7 +808,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
conn
|> add_link_headers(:following, followers, user)
|> put_view(AccountView)
- |> render("accounts.json", %{users: followers, as: :user})
+ |> render("accounts.json", %{for: for_user, users: followers, as: :user})
end
end
@@ -787,7 +816,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
with {:ok, follow_requests} <- User.get_follow_requests(followed) do
conn
|> put_view(AccountView)
- |> render("accounts.json", %{users: follow_requests, as: :user})
+ |> render("accounts.json", %{for: followed, users: follow_requests, as: :user})
end
end
@@ -1081,6 +1110,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
ActivityPub.fetch_activities([], params)
|> Enum.reverse()
+ user = Repo.preload(user, bookmarks: :activity)
+
conn
|> add_link_headers(:favourites, activities)
|> put_view(StatusView)
@@ -1124,15 +1155,20 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
end
- def bookmarks(%{assigns: %{user: user}} = conn, _) do
+ def bookmarks(%{assigns: %{user: user}} = conn, params) do
user = User.get_cached_by_id(user.id)
+ user = Repo.preload(user, bookmarks: :activity)
+
+ bookmarks =
+ Bookmark.for_user_query(user.id)
+ |> Pagination.fetch_paginated(params)
activities =
- user.bookmarks
- |> Enum.map(fn id -> Activity.get_create_by_object_ap_id(id) end)
- |> Enum.reverse()
+ bookmarks
+ |> Enum.map(fn b -> b.activity end)
conn
+ |> add_link_headers(:bookmarks, bookmarks)
|> put_view(StatusView)
|> render("index.json", %{activities: activities, for: user, as: :activity})
end
@@ -1207,7 +1243,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
{:ok, users} = Pleroma.List.get_following(list) do
conn
|> put_view(AccountView)
- |> render("accounts.json", %{users: users, as: :user})
+ |> render("accounts.json", %{for: user, users: users, as: :user})
end
end
@@ -1238,6 +1274,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|> ActivityPub.fetch_activities_bounded(following, params)
|> Enum.reverse()
+ user = Repo.preload(user, bookmarks: :activity)
+
conn
|> put_view(StatusView)
|> render("index.json", %{activities: activities, for: user, as: :activity})
@@ -1265,8 +1303,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
initial_state =
%{
meta: %{
- streaming_api_base_url:
- String.replace(Pleroma.Web.Endpoint.static_url(), "http", "ws"),
+ streaming_api_base_url: Pleroma.Web.Endpoint.websocket_url(),
access_token: token,
locale: "en",
domain: Pleroma.Web.Endpoint.host(),
@@ -1623,7 +1660,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
x,
"id",
case User.get_or_fetch(x["acct"]) do
- %{id: id} -> id
+ {:ok, %User{id: id}} -> id
_ -> 0
end
)
diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex
index d87fdb15d..779b9a382 100644
--- a/lib/pleroma/web/mastodon_api/views/account_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/account_view.ex
@@ -113,21 +113,23 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
bot: bot,
source: %{
note: "",
- privacy: user_info.default_scope,
- sensitive: false
+ sensitive: false,
+ pleroma: %{}
},
# Pleroma extension
- pleroma:
- %{
- confirmation_pending: user_info.confirmation_pending,
- tags: user.tags,
- is_moderator: user.info.is_moderator,
- is_admin: user.info.is_admin,
- relationship: relationship
- }
- |> with_notification_settings(user, opts[:for])
+ pleroma: %{
+ confirmation_pending: user_info.confirmation_pending,
+ tags: user.tags,
+ hide_followers: user.info.hide_followers,
+ hide_follows: user.info.hide_follows,
+ hide_favorites: user.info.hide_favorites,
+ relationship: relationship
+ }
}
+ |> maybe_put_role(user, opts[:for])
+ |> maybe_put_settings(user, opts[:for], user_info)
+ |> maybe_put_notification_settings(user, opts[:for])
end
defp username_from_nickname(string) when is_binary(string) do
@@ -136,9 +138,37 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
defp username_from_nickname(_), do: nil
- defp with_notification_settings(data, %User{id: user_id} = user, %User{id: user_id}) do
- Map.put(data, :notification_settings, user.info.notification_settings)
+ defp maybe_put_settings(
+ data,
+ %User{id: user_id} = user,
+ %User{id: user_id},
+ user_info
+ ) do
+ data
+ |> Kernel.put_in([:source, :privacy], user_info.default_scope)
+ |> Kernel.put_in([:source, :pleroma, :show_role], user.info.show_role)
+ |> Kernel.put_in([:source, :pleroma, :no_rich_text], user.info.no_rich_text)
+ end
+
+ defp maybe_put_settings(data, _, _, _), do: data
+
+ defp maybe_put_role(data, %User{info: %{show_role: true}} = user, _) do
+ data
+ |> Kernel.put_in([:pleroma, :is_admin], user.info.is_admin)
+ |> Kernel.put_in([:pleroma, :is_moderator], user.info.is_moderator)
+ end
+
+ defp maybe_put_role(data, %User{id: user_id} = user, %User{id: user_id}) do
+ data
+ |> Kernel.put_in([:pleroma, :is_admin], user.info.is_admin)
+ |> Kernel.put_in([:pleroma, :is_moderator], user.info.is_moderator)
+ end
+
+ defp maybe_put_role(data, _, _), do: data
+
+ defp maybe_put_notification_settings(data, %User{id: user_id} = user, %User{id: user_id}) do
+ Kernel.put_in(data, [:pleroma, :notification_settings], user.info.notification_settings)
end
- defp with_notification_settings(data, _, _), do: data
+ defp maybe_put_notification_settings(data, _, _), do: data
end
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index 7dd80d708..62d064d71 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -85,7 +85,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
activity_object = Object.normalize(activity)
favorited = opts[:for] && opts[:for].ap_id in (activity_object.data["likes"] || [])
- bookmarked = opts[:for] && activity_object.data["id"] in opts[:for].bookmarks
+
+ bookmarked = opts[:for] && CommonAPI.bookmarked?(opts[:for], reblogged_activity)
mentions =
activity.recipients
@@ -148,7 +149,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
favorited = opts[:for] && opts[:for].ap_id in (object.data["likes"] || [])
- bookmarked = opts[:for] && object.data["id"] in opts[:for].bookmarks
+ bookmarked = opts[:for] && CommonAPI.bookmarked?(opts[:for], activity)
attachment_data = object.data["attachment"] || []
attachments = render_many(attachment_data, StatusView, "attachment.json", as: :attachment)
diff --git a/lib/pleroma/web/media_proxy/media_proxy.ex b/lib/pleroma/web/media_proxy/media_proxy.ex
index 3bd2affe9..5762e767b 100644
--- a/lib/pleroma/web/media_proxy/media_proxy.ex
+++ b/lib/pleroma/web/media_proxy/media_proxy.ex
@@ -13,32 +13,44 @@ defmodule Pleroma.Web.MediaProxy do
def url(url) do
config = Application.get_env(:pleroma, :media_proxy, [])
+ domain = URI.parse(url).host
- if !Keyword.get(config, :enabled, false) or String.starts_with?(url, Pleroma.Web.base_url()) do
- url
- else
- secret = Application.get_env(:pleroma, Pleroma.Web.Endpoint)[:secret_key_base]
-
- # Must preserve `%2F` for compatibility with S3
- # https://git.pleroma.social/pleroma/pleroma/issues/580
- replacement = get_replacement(url, ":2F:")
-
- # The URL is url-decoded and encoded again to ensure it is correctly encoded and not twice.
- base64 =
+ cond do
+ !Keyword.get(config, :enabled, false) or String.starts_with?(url, Pleroma.Web.base_url()) ->
url
- |> String.replace("%2F", replacement)
- |> URI.decode()
- |> URI.encode()
- |> String.replace(replacement, "%2F")
- |> Base.url_encode64(@base64_opts)
- sig = :crypto.hmac(:sha, secret, base64)
- sig64 = sig |> Base.url_encode64(@base64_opts)
+ Enum.any?(Pleroma.Config.get([:media_proxy, :whitelist]), fn pattern ->
+ String.equivalent?(domain, pattern)
+ end) ->
+ url
- build_url(sig64, base64, filename(url))
+ true ->
+ encode_url(url)
end
end
+ def encode_url(url) do
+ secret = Application.get_env(:pleroma, Pleroma.Web.Endpoint)[:secret_key_base]
+
+ # Must preserve `%2F` for compatibility with S3
+ # https://git.pleroma.social/pleroma/pleroma/issues/580
+ replacement = get_replacement(url, ":2F:")
+
+ # The URL is url-decoded and encoded again to ensure it is correctly encoded and not twice.
+ base64 =
+ url
+ |> String.replace("%2F", replacement)
+ |> URI.decode()
+ |> URI.encode()
+ |> String.replace(replacement, "%2F")
+ |> Base.url_encode64(@base64_opts)
+
+ sig = :crypto.hmac(:sha, secret, base64)
+ sig64 = sig |> Base.url_encode64(@base64_opts)
+
+ build_url(sig64, base64, filename(url))
+ end
+
def decode_url(sig, url) do
secret = Application.get_env(:pleroma, Pleroma.Web.Endpoint)[:secret_key_base]
sig = Base.url_decode64!(sig, @base64_opts)
diff --git a/lib/pleroma/web/oauth/app.ex b/lib/pleroma/web/oauth/app.ex
index 3476da484..bccc2ac96 100644
--- a/lib/pleroma/web/oauth/app.ex
+++ b/lib/pleroma/web/oauth/app.ex
@@ -6,6 +6,7 @@ defmodule Pleroma.Web.OAuth.App do
use Ecto.Schema
import Ecto.Changeset
+ @type t :: %__MODULE__{}
schema "apps" do
field(:client_name, :string)
field(:redirect_uris, :string)
diff --git a/lib/pleroma/web/oauth/authorization.ex b/lib/pleroma/web/oauth/authorization.ex
index 3461f9983..ca3901cc4 100644
--- a/lib/pleroma/web/oauth/authorization.ex
+++ b/lib/pleroma/web/oauth/authorization.ex
@@ -13,6 +13,7 @@ defmodule Pleroma.Web.OAuth.Authorization do
import Ecto.Changeset
import Ecto.Query
+ @type t :: %__MODULE__{}
schema "oauth_authorizations" do
field(:token, :string)
field(:scopes, {:array, :string}, default: [])
@@ -63,4 +64,11 @@ defmodule Pleroma.Web.OAuth.Authorization do
)
|> Repo.delete_all()
end
+
+ @doc "gets auth for app by token"
+ @spec get_by_token(App.t(), String.t()) :: {:ok, t()} | {:error, :not_found}
+ def get_by_token(%App{id: app_id} = _app, token) do
+ from(t in __MODULE__, where: t.app_id == ^app_id and t.token == ^token)
+ |> Repo.find_resource()
+ end
end
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index 688eaca11..e3c01217d 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -13,11 +13,15 @@ defmodule Pleroma.Web.OAuth.OAuthController do
alias Pleroma.Web.OAuth.App
alias Pleroma.Web.OAuth.Authorization
alias Pleroma.Web.OAuth.Token
+ alias Pleroma.Web.OAuth.Token.Strategy.RefreshToken
+ alias Pleroma.Web.OAuth.Token.Strategy.Revoke, as: RevokeToken
import Pleroma.Web.ControllerHelper, only: [oauth_scopes: 2]
if Pleroma.Config.oauth_consumer_enabled?(), do: plug(Ueberauth)
+ @expires_in Pleroma.Config.get([:oauth2, :token_expires_in], 600)
+
plug(:fetch_session)
plug(:fetch_flash)
@@ -138,25 +142,33 @@ defmodule Pleroma.Web.OAuth.OAuthController do
Authenticator.handle_error(conn, error)
end
+ @doc "Renew access_token with refresh_token"
+ def token_exchange(
+ conn,
+ %{"grant_type" => "refresh_token", "refresh_token" => token} = params
+ ) do
+ with %App{} = app <- get_app_from_request(conn, params),
+ {:ok, %{user: user} = token} <- Token.get_by_refresh_token(app, token),
+ {:ok, token} <- RefreshToken.grant(token) do
+ response_attrs = %{created_at: Token.Utils.format_created_at(token)}
+
+ json(conn, response_token(user, token, response_attrs))
+ else
+ _error ->
+ put_status(conn, 400)
+ |> json(%{error: "Invalid credentials"})
+ end
+ end
+
def token_exchange(conn, %{"grant_type" => "authorization_code"} = params) do
with %App{} = app <- get_app_from_request(conn, params),
- fixed_token = fix_padding(params["code"]),
- %Authorization{} = auth <-
- Repo.get_by(Authorization, token: fixed_token, app_id: app.id),
+ fixed_token = Token.Utils.fix_padding(params["code"]),
+ {:ok, auth} <- Authorization.get_by_token(app, fixed_token),
%User{} = user <- User.get_cached_by_id(auth.user_id),
- {:ok, token} <- Token.exchange_token(app, auth),
- {:ok, inserted_at} <- DateTime.from_naive(token.inserted_at, "Etc/UTC") do
- response = %{
- token_type: "Bearer",
- access_token: token.token,
- refresh_token: token.refresh_token,
- created_at: DateTime.to_unix(inserted_at),
- expires_in: 60 * 10,
- scope: Enum.join(token.scopes, " "),
- me: user.ap_id
- }
-
- json(conn, response)
+ {:ok, token} <- Token.exchange_token(app, auth) do
+ response_attrs = %{created_at: Token.Utils.format_created_at(token)}
+
+ json(conn, response_token(user, token, response_attrs))
else
_error ->
put_status(conn, 400)
@@ -177,16 +189,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
true <- Enum.any?(scopes),
{:ok, auth} <- Authorization.create_authorization(app, user, scopes),
{:ok, token} <- Token.exchange_token(app, auth) do
- response = %{
- token_type: "Bearer",
- access_token: token.token,
- refresh_token: token.refresh_token,
- expires_in: 60 * 10,
- scope: Enum.join(token.scopes, " "),
- me: user.ap_id
- }
-
- json(conn, response)
+ json(conn, response_token(user, token))
else
{:auth_active, false} ->
# Per https://github.com/tootsuite/mastodon/blob/
@@ -218,10 +221,12 @@ defmodule Pleroma.Web.OAuth.OAuthController do
token_exchange(conn, params)
end
- def token_revoke(conn, %{"token" => token} = params) do
+ # Bad request
+ def token_exchange(conn, params), do: bad_request(conn, params)
+
+ def token_revoke(conn, %{"token" => _token} = params) do
with %App{} = app <- get_app_from_request(conn, params),
- %Token{} = token <- Repo.get_by(Token, token: token, app_id: app.id),
- {:ok, %Token{}} <- Repo.delete(token) do
+ {:ok, _token} <- RevokeToken.revoke(app, params) do
json(conn, %{})
else
_error ->
@@ -230,6 +235,15 @@ defmodule Pleroma.Web.OAuth.OAuthController do
end
end
+ def token_revoke(conn, params), do: bad_request(conn, params)
+
+ # Response for bad request
+ defp bad_request(conn, _) do
+ conn
+ |> put_status(500)
+ |> json(%{error: "Bad request"})
+ end
+
@doc "Prepares OAuth request to provider for Ueberauth"
def prepare_request(conn, %{"provider" => provider, "authorization" => auth_attrs}) do
scope =
@@ -278,25 +292,22 @@ defmodule Pleroma.Web.OAuth.OAuthController do
params = callback_params(params)
with {:ok, registration} <- Authenticator.get_registration(conn) do
- user = Repo.preload(registration, :user).user
auth_attrs = Map.take(params, ~w(client_id redirect_uri scope scopes state))
- if user do
- create_authorization(
- conn,
- %{"authorization" => auth_attrs},
- user: user
- )
- else
- registration_params =
- Map.merge(auth_attrs, %{
- "nickname" => Registration.nickname(registration),
- "email" => Registration.email(registration)
- })
+ case Repo.get_assoc(registration, :user) do
+ {:ok, user} ->
+ create_authorization(conn, %{"authorization" => auth_attrs}, user: user)
- conn
- |> put_session(:registration_id, registration.id)
- |> registration_details(%{"authorization" => registration_params})
+ _ ->
+ registration_params =
+ Map.merge(auth_attrs, %{
+ "nickname" => Registration.nickname(registration),
+ "email" => Registration.email(registration)
+ })
+
+ conn
+ |> put_session(:registration_id, registration.id)
+ |> registration_details(%{"authorization" => registration_params})
end
else
_ ->
@@ -399,36 +410,30 @@ defmodule Pleroma.Web.OAuth.OAuthController do
end
end
- # XXX - for whatever reason our token arrives urlencoded, but Plug.Conn should be
- # decoding it. Investigate sometime.
- defp fix_padding(token) do
- token
- |> URI.decode()
- |> Base.url_decode64!(padding: false)
- |> Base.url_encode64(padding: false)
+ defp get_app_from_request(conn, params) do
+ conn
+ |> fetch_client_credentials(params)
+ |> fetch_client
end
- defp get_app_from_request(conn, params) do
- # Per RFC 6749, HTTP Basic is preferred to body params
- {client_id, client_secret} =
- with ["Basic " <> encoded] <- get_req_header(conn, "authorization"),
- {:ok, decoded} <- Base.decode64(encoded),
- [id, secret] <-
- String.split(decoded, ":")
- |> Enum.map(fn s -> URI.decode_www_form(s) end) do
- {id, secret}
- else
- _ -> {params["client_id"], params["client_secret"]}
- end
+ defp fetch_client({id, secret}) when is_binary(id) and is_binary(secret) do
+ Repo.get_by(App, client_id: id, client_secret: secret)
+ end
- if client_id && client_secret do
- Repo.get_by(
- App,
- client_id: client_id,
- client_secret: client_secret
- )
+ defp fetch_client({_id, _secret}), do: nil
+
+ defp fetch_client_credentials(conn, params) do
+ # Per RFC 6749, HTTP Basic is preferred to body params
+ with ["Basic " <> encoded] <- get_req_header(conn, "authorization"),
+ {:ok, decoded} <- Base.decode64(encoded),
+ [id, secret] <-
+ Enum.map(
+ String.split(decoded, ":"),
+ fn s -> URI.decode_www_form(s) end
+ ) do
+ {id, secret}
else
- nil
+ _ -> {params["client_id"], params["client_secret"]}
end
end
@@ -441,4 +446,16 @@ defmodule Pleroma.Web.OAuth.OAuthController do
defp put_session_registration_id(conn, registration_id),
do: put_session(conn, :registration_id, registration_id)
+
+ defp response_token(%User{} = user, token, opts \\ %{}) do
+ %{
+ token_type: "Bearer",
+ access_token: token.token,
+ refresh_token: token.refresh_token,
+ expires_in: @expires_in,
+ scope: Enum.join(token.scopes, " "),
+ me: user.ap_id
+ }
+ |> Map.merge(opts)
+ end
end
diff --git a/lib/pleroma/web/oauth/token.ex b/lib/pleroma/web/oauth/token.ex
index 399140003..4e5d1d118 100644
--- a/lib/pleroma/web/oauth/token.ex
+++ b/lib/pleroma/web/oauth/token.ex
@@ -6,6 +6,7 @@ defmodule Pleroma.Web.OAuth.Token do
use Ecto.Schema
import Ecto.Query
+ import Ecto.Changeset
alias Pleroma.Repo
alias Pleroma.User
@@ -13,6 +14,9 @@ defmodule Pleroma.Web.OAuth.Token do
alias Pleroma.Web.OAuth.Authorization
alias Pleroma.Web.OAuth.Token
+ @expires_in Pleroma.Config.get([:oauth2, :token_expires_in], 600)
+ @type t :: %__MODULE__{}
+
schema "oauth_tokens" do
field(:token, :string)
field(:refresh_token, :string)
@@ -24,28 +28,67 @@ defmodule Pleroma.Web.OAuth.Token do
timestamps()
end
+ @doc "Gets token for app by access token"
+ @spec get_by_token(App.t(), String.t()) :: {:ok, t()} | {:error, :not_found}
+ def get_by_token(%App{id: app_id} = _app, token) do
+ from(t in __MODULE__, where: t.app_id == ^app_id and t.token == ^token)
+ |> Repo.find_resource()
+ end
+
+ @doc "Gets token for app by refresh token"
+ @spec get_by_refresh_token(App.t(), String.t()) :: {:ok, t()} | {:error, :not_found}
+ def get_by_refresh_token(%App{id: app_id} = _app, token) do
+ from(t in __MODULE__,
+ where: t.app_id == ^app_id and t.refresh_token == ^token,
+ preload: [:user]
+ )
+ |> Repo.find_resource()
+ end
+
def exchange_token(app, auth) do
with {:ok, auth} <- Authorization.use_token(auth),
true <- auth.app_id == app.id do
- create_token(app, User.get_cached_by_id(auth.user_id), auth.scopes)
+ create_token(
+ app,
+ User.get_cached_by_id(auth.user_id),
+ %{scopes: auth.scopes}
+ )
end
end
- def create_token(%App{} = app, %User{} = user, scopes \\ nil) do
- scopes = scopes || app.scopes
- token = :crypto.strong_rand_bytes(32) |> Base.url_encode64(padding: false)
- refresh_token = :crypto.strong_rand_bytes(32) |> Base.url_encode64(padding: false)
-
- token = %Token{
- token: token,
- refresh_token: refresh_token,
- scopes: scopes,
- user_id: user.id,
- app_id: app.id,
- valid_until: NaiveDateTime.add(NaiveDateTime.utc_now(), 60 * 10)
- }
-
- Repo.insert(token)
+ defp put_token(changeset) do
+ changeset
+ |> change(%{token: Token.Utils.generate_token()})
+ |> validate_required([:token])
+ |> unique_constraint(:token)
+ end
+
+ defp put_refresh_token(changeset, attrs) do
+ refresh_token = Map.get(attrs, :refresh_token, Token.Utils.generate_token())
+
+ changeset
+ |> change(%{refresh_token: refresh_token})
+ |> validate_required([:refresh_token])
+ |> unique_constraint(:refresh_token)
+ end
+
+ defp put_valid_until(changeset, attrs) do
+ expires_in =
+ Map.get(attrs, :valid_until, NaiveDateTime.add(NaiveDateTime.utc_now(), @expires_in))
+
+ changeset
+ |> change(%{valid_until: expires_in})
+ |> validate_required([:valid_until])
+ end
+
+ def create_token(%App{} = app, %User{} = user, attrs \\ %{}) do
+ %__MODULE__{user_id: user.id, app_id: app.id}
+ |> cast(%{scopes: attrs[:scopes] || app.scopes}, [:scopes])
+ |> validate_required([:scopes, :user_id, :app_id])
+ |> put_valid_until(attrs)
+ |> put_token
+ |> put_refresh_token(attrs)
+ |> Repo.insert()
end
def delete_user_tokens(%User{id: user_id}) do
@@ -73,4 +116,10 @@ defmodule Pleroma.Web.OAuth.Token do
|> Repo.all()
|> Repo.preload(:app)
end
+
+ def is_expired?(%__MODULE__{valid_until: valid_until}) do
+ NaiveDateTime.diff(NaiveDateTime.utc_now(), valid_until) > 0
+ end
+
+ def is_expired?(_), do: false
end
diff --git a/lib/pleroma/web/oauth/token/strategy/refresh_token.ex b/lib/pleroma/web/oauth/token/strategy/refresh_token.ex
new file mode 100644
index 000000000..7df0be14e
--- /dev/null
+++ b/lib/pleroma/web/oauth/token/strategy/refresh_token.ex
@@ -0,0 +1,54 @@
+defmodule Pleroma.Web.OAuth.Token.Strategy.RefreshToken do
+ @moduledoc """
+ Functions for dealing with refresh token strategy.
+ """
+
+ alias Pleroma.Config
+ alias Pleroma.Repo
+ alias Pleroma.Web.OAuth.Token
+ alias Pleroma.Web.OAuth.Token.Strategy.Revoke
+
+ @doc """
+ Will grant access token by refresh token.
+ """
+ @spec grant(Token.t()) :: {:ok, Token.t()} | {:error, any()}
+ def grant(token) do
+ access_token = Repo.preload(token, [:user, :app])
+
+ result =
+ Repo.transaction(fn ->
+ token_params = %{
+ app: access_token.app,
+ user: access_token.user,
+ scopes: access_token.scopes
+ }
+
+ access_token
+ |> revoke_access_token()
+ |> create_access_token(token_params)
+ end)
+
+ case result do
+ {:ok, {:error, reason}} -> {:error, reason}
+ {:ok, {:ok, token}} -> {:ok, token}
+ {:error, reason} -> {:error, reason}
+ end
+ end
+
+ defp revoke_access_token(token) do
+ Revoke.revoke(token)
+ end
+
+ defp create_access_token({:error, error}, _), do: {:error, error}
+
+ defp create_access_token({:ok, token}, %{app: app, user: user} = token_params) do
+ Token.create_token(app, user, add_refresh_token(token_params, token.refresh_token))
+ end
+
+ defp add_refresh_token(params, token) do
+ case Config.get([:oauth2, :issue_new_refresh_token], false) do
+ true -> Map.put(params, :refresh_token, token)
+ false -> params
+ end
+ end
+end
diff --git a/lib/pleroma/web/oauth/token/strategy/revoke.ex b/lib/pleroma/web/oauth/token/strategy/revoke.ex
new file mode 100644
index 000000000..dea63ca54
--- /dev/null
+++ b/lib/pleroma/web/oauth/token/strategy/revoke.ex
@@ -0,0 +1,22 @@
+defmodule Pleroma.Web.OAuth.Token.Strategy.Revoke do
+ @moduledoc """
+ Functions for dealing with revocation.
+ """
+
+ alias Pleroma.Repo
+ alias Pleroma.Web.OAuth.App
+ alias Pleroma.Web.OAuth.Token
+
+ @doc "Finds and revokes access token for app and by token"
+ @spec revoke(App.t(), map()) :: {:ok, Token.t()} | {:error, :not_found | Ecto.Changeset.t()}
+ def revoke(%App{} = app, %{"token" => token} = _attrs) do
+ with {:ok, token} <- Token.get_by_token(app, token),
+ do: revoke(token)
+ end
+
+ @doc "Revokes access token"
+ @spec revoke(Token.t()) :: {:ok, Token.t()} | {:error, Ecto.Changeset.t()}
+ def revoke(%Token{} = token) do
+ Repo.delete(token)
+ end
+end
diff --git a/lib/pleroma/web/oauth/token/utils.ex b/lib/pleroma/web/oauth/token/utils.ex
new file mode 100644
index 000000000..a81560a1c
--- /dev/null
+++ b/lib/pleroma/web/oauth/token/utils.ex
@@ -0,0 +1,30 @@
+defmodule Pleroma.Web.OAuth.Token.Utils do
+ @moduledoc """
+ Auxiliary functions for dealing with tokens.
+ """
+
+ @doc "convert token inserted_at to unix timestamp"
+ def format_created_at(%{inserted_at: inserted_at} = _token) do
+ inserted_at
+ |> DateTime.from_naive!("Etc/UTC")
+ |> DateTime.to_unix()
+ end
+
+ @doc false
+ @spec generate_token(keyword()) :: binary()
+ def generate_token(opts \\ []) do
+ opts
+ |> Keyword.get(:size, 32)
+ |> :crypto.strong_rand_bytes()
+ |> Base.url_encode64(padding: false)
+ end
+
+ # XXX - for whatever reason our token arrives urlencoded, but Plug.Conn should be
+ # decoding it. Investigate sometime.
+ def fix_padding(token) do
+ token
+ |> URI.decode()
+ |> Base.url_decode64!(padding: false)
+ |> Base.url_encode64(padding: false)
+ end
+end
diff --git a/lib/pleroma/web/push/impl.ex b/lib/pleroma/web/push/impl.ex
index 2233480c5..35d3ff07c 100644
--- a/lib/pleroma/web/push/impl.ex
+++ b/lib/pleroma/web/push/impl.ex
@@ -21,8 +21,10 @@ defmodule Pleroma.Web.Push.Impl do
@doc "Performs sending notifications for user subscriptions"
@spec perform(Notification.t()) :: list(any) | :error
def perform(
- %{activity: %{data: %{"type" => activity_type}, id: activity_id}, user_id: user_id} =
- notif
+ %{
+ activity: %{data: %{"type" => activity_type}, id: activity_id} = activity,
+ user_id: user_id
+ } = notif
)
when activity_type in @types do
actor = User.get_cached_by_ap_id(notif.activity.data["actor"])
@@ -30,13 +32,14 @@ defmodule Pleroma.Web.Push.Impl do
type = Activity.mastodon_notification_type(notif.activity)
gcm_api_key = Application.get_env(:web_push_encryption, :gcm_api_key)
avatar_url = User.avatar_url(actor)
+ object = Object.normalize(activity)
for subscription <- fetch_subsriptions(user_id),
get_in(subscription.data, ["alerts", type]) do
%{
title: format_title(notif),
access_token: subscription.token.token,
- body: format_body(notif, actor),
+ body: format_body(notif, actor, object),
notification_id: notif.id,
notification_type: type,
icon: avatar_url,
@@ -95,25 +98,25 @@ defmodule Pleroma.Web.Push.Impl do
end
def format_body(
- %{activity: %{data: %{"type" => "Create", "object" => %{"content" => content}}}},
- actor
+ %{activity: %{data: %{"type" => "Create"}}},
+ actor,
+ %{data: %{"content" => content}}
) do
"@#{actor.nickname}: #{Utils.scrub_html_and_truncate(content, 80)}"
end
def format_body(
- %{activity: %{data: %{"type" => "Announce", "object" => activity_id}}},
- actor
+ %{activity: %{data: %{"type" => "Announce"}}},
+ actor,
+ %{data: %{"content" => content}}
) do
- %Activity{data: %{"object" => %{"id" => object_id}}} = Activity.get_by_ap_id(activity_id)
- %Object{data: %{"content" => content}} = Object.get_by_ap_id(object_id)
-
"@#{actor.nickname} repeated: #{Utils.scrub_html_and_truncate(content, 80)}"
end
def format_body(
%{activity: %{data: %{"type" => type}}},
- actor
+ actor,
+ _object
)
when type in ["Follow", "Like"] do
case type do
diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
index 6c8c2fe24..7b7fd912b 100644
--- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex
+++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
@@ -352,7 +352,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
def delete_account(%{assigns: %{user: user}} = conn, params) do
case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
{:ok, user} ->
- Task.start(fn -> User.delete(user) end)
+ User.delete(user)
json(conn, %{status: "success"})
{:error, msg} ->
diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex
index 2353a95a8..1e48b0b39 100644
--- a/lib/pleroma/web/twitter_api/twitter_api.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api.ex
@@ -296,7 +296,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
end
def get_external_profile(for_user, uri) do
- with %User{} = user <- User.get_or_fetch(uri) do
+ with {:ok, %User{} = user} <- User.get_or_fetch(uri) do
{:ok, UserView.render("show.json", %{user: user, for: for_user})}
else
_e ->
diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
index 79ed9dad2..ef7b6fe65 100644
--- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
@@ -9,6 +9,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
alias Ecto.Changeset
alias Pleroma.Activity
+ alias Pleroma.Formatter
alias Pleroma.Notification
alias Pleroma.Object
alias Pleroma.Repo
@@ -653,7 +654,22 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
defp parse_profile_bio(user, params) do
if bio = params["description"] do
- Map.put(params, "bio", User.parse_bio(bio, user))
+ emojis_text = (params["description"] || "") <> " " <> (params["name"] || "")
+
+ emojis =
+ ((user.info.emoji || []) ++ Formatter.get_emoji_map(emojis_text))
+ |> Enum.dedup()
+
+ user_info =
+ user.info
+ |> Map.put(
+ "emoji",
+ emojis
+ )
+
+ params
+ |> Map.put("bio", User.parse_bio(bio, user))
+ |> Map.put("info", user_info)
else
params
end
diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex
index 0791ed760..f0a4ddbd3 100644
--- a/lib/pleroma/web/twitter_api/views/user_view.ex
+++ b/lib/pleroma/web/twitter_api/views/user_view.ex
@@ -67,6 +67,13 @@ defmodule Pleroma.Web.TwitterAPI.UserView do
{String.trim(name, ":"), url}
end)
+ emoji = Enum.dedup(emoji ++ user.info.emoji)
+
+ description_html =
+ (user.bio || "")
+ |> HTML.filter_tags(User.html_filter_policy(for_user))
+ |> Formatter.emojify(emoji)
+
# ``fields`` is an array of mastodon profile field, containing ``{"name": "…", "value": "…"}``.
# For example: [{"name": "Pronoun", "value": "she/her"}, …]
fields =
@@ -74,58 +81,49 @@ defmodule Pleroma.Web.TwitterAPI.UserView do
|> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end)
|> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end)
- data = %{
- "created_at" => user.inserted_at |> Utils.format_naive_asctime(),
- "description" => HTML.strip_tags((user.bio || "") |> String.replace("<br>", "\n")),
- "description_html" => HTML.filter_tags(user.bio, User.html_filter_policy(for_user)),
- "favourites_count" => 0,
- "followers_count" => user_info[:follower_count],
- "following" => following,
- "follows_you" => follows_you,
- "statusnet_blocking" => statusnet_blocking,
- "friends_count" => user_info[:following_count],
- "id" => user.id,
- "name" => user.name || user.nickname,
- "name_html" =>
- if(user.name,
- do: HTML.strip_tags(user.name) |> Formatter.emojify(emoji),
- else: user.nickname
- ),
- "profile_image_url" => image,
- "profile_image_url_https" => image,
- "profile_image_url_profile_size" => image,
- "profile_image_url_original" => image,
- "rights" => %{
- "delete_others_notice" => !!user.info.is_moderator,
- "admin" => !!user.info.is_admin
- },
- "screen_name" => user.nickname,
- "statuses_count" => user_info[:note_count],
- "statusnet_profile_url" => user.ap_id,
- "cover_photo" => User.banner_url(user) |> MediaProxy.url(),
- "background_image" => image_url(user.info.background) |> MediaProxy.url(),
- "is_local" => user.local,
- "locked" => user.info.locked,
- "default_scope" => user.info.default_scope,
- "no_rich_text" => user.info.no_rich_text,
- "hide_followers" => user.info.hide_followers,
- "hide_follows" => user.info.hide_follows,
- "fields" => fields,
-
- # Pleroma extension
- "pleroma" =>
- %{
- "confirmation_pending" => user_info.confirmation_pending,
- "tags" => user.tags
- }
- |> maybe_with_activation_status(user, for_user)
- }
-
data =
- if(user.info.is_admin || user.info.is_moderator,
- do: maybe_with_role(data, user, for_user),
- else: data
- )
+ %{
+ "created_at" => user.inserted_at |> Utils.format_naive_asctime(),
+ "description" => HTML.strip_tags((user.bio || "") |> String.replace("<br>", "\n")),
+ "description_html" => description_html,
+ "favourites_count" => 0,
+ "followers_count" => user_info[:follower_count],
+ "following" => following,
+ "follows_you" => follows_you,
+ "statusnet_blocking" => statusnet_blocking,
+ "friends_count" => user_info[:following_count],
+ "id" => user.id,
+ "name" => user.name || user.nickname,
+ "name_html" =>
+ if(user.name,
+ do: HTML.strip_tags(user.name) |> Formatter.emojify(emoji),
+ else: user.nickname
+ ),
+ "profile_image_url" => image,
+ "profile_image_url_https" => image,
+ "profile_image_url_profile_size" => image,
+ "profile_image_url_original" => image,
+ "screen_name" => user.nickname,
+ "statuses_count" => user_info[:note_count],
+ "statusnet_profile_url" => user.ap_id,
+ "cover_photo" => User.banner_url(user) |> MediaProxy.url(),
+ "background_image" => image_url(user.info.background) |> MediaProxy.url(),
+ "is_local" => user.local,
+ "locked" => user.info.locked,
+ "hide_followers" => user.info.hide_followers,
+ "hide_follows" => user.info.hide_follows,
+ "fields" => fields,
+
+ # Pleroma extension
+ "pleroma" =>
+ %{
+ "confirmation_pending" => user_info.confirmation_pending,
+ "tags" => user.tags
+ }
+ |> maybe_with_activation_status(user, for_user)
+ }
+ |> maybe_with_user_settings(user, for_user)
+ |> maybe_with_role(user, for_user)
if assigns[:token] do
Map.put(data, "token", token_string(assigns[:token]))
@@ -141,15 +139,35 @@ defmodule Pleroma.Web.TwitterAPI.UserView do
defp maybe_with_activation_status(data, _, _), do: data
defp maybe_with_role(data, %User{id: id} = user, %User{id: id}) do
- Map.merge(data, %{"role" => role(user), "show_role" => user.info.show_role})
+ Map.merge(data, %{
+ "role" => role(user),
+ "show_role" => user.info.show_role,
+ "rights" => %{
+ "delete_others_notice" => !!user.info.is_moderator,
+ "admin" => !!user.info.is_admin
+ }
+ })
end
defp maybe_with_role(data, %User{info: %{show_role: true}} = user, _user) do
- Map.merge(data, %{"role" => role(user)})
+ Map.merge(data, %{
+ "role" => role(user),
+ "rights" => %{
+ "delete_others_notice" => !!user.info.is_moderator,
+ "admin" => !!user.info.is_admin
+ }
+ })
end
defp maybe_with_role(data, _, _), do: data
+ defp maybe_with_user_settings(data, %User{info: info, id: id} = _user, %User{id: id}) do
+ data
+ |> Kernel.put_in(["default_scope"], info.default_scope)
+ |> Kernel.put_in(["no_rich_text"], info.no_rich_text)
+ end
+
+ defp maybe_with_user_settings(data, _, _), do: data
defp role(%User{info: %{:is_admin => true}}), do: "admin"
defp role(%User{info: %{:is_moderator => true}}), do: "moderator"
defp role(_), do: "member"