Merge branch 'develop' into feature/compat/push-subscriptions
# Conflicts: # lib/pleroma/application.ex # lib/pleroma/plugs/oauth_plug.ex
This commit is contained in:
commit
4944498133
119 changed files with 3725 additions and 1956 deletions
|
|
@ -42,7 +42,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
defp check_actor_is_active(actor) do
|
||||
if not is_nil(actor) do
|
||||
with user <- User.get_cached_by_ap_id(actor),
|
||||
false <- !!user.info["deactivated"] do
|
||||
false <- user.info.deactivated do
|
||||
:ok
|
||||
else
|
||||
_e -> :reject
|
||||
|
|
@ -509,8 +509,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
end
|
||||
|
||||
defp restrict_blocked(query, %{"blocking_user" => %User{info: info}}) do
|
||||
blocks = info["blocks"] || []
|
||||
domain_blocks = info["domain_blocks"] || []
|
||||
blocks = info.blocks || []
|
||||
domain_blocks = info.domain_blocks || []
|
||||
|
||||
from(
|
||||
activity in query,
|
||||
|
|
@ -572,11 +572,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
|> Enum.reverse()
|
||||
end
|
||||
|
||||
def upload(file, size_limit \\ nil) do
|
||||
with data <-
|
||||
Upload.store(file, Application.get_env(:pleroma, :instance)[:dedupe_media], size_limit),
|
||||
false <- is_nil(data) do
|
||||
Repo.insert(%Object{data: data})
|
||||
def upload(file, opts \\ []) do
|
||||
with {:ok, data} <- Upload.store(file, opts) do
|
||||
obj_data =
|
||||
if opts[:actor] do
|
||||
Map.put(data, "actor", opts[:actor])
|
||||
else
|
||||
data
|
||||
end
|
||||
|
||||
Repo.insert(%Object{data: obj_data})
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -678,7 +683,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
remote_inboxes =
|
||||
(Pleroma.Web.Salmon.remote_users(activity) ++ followers)
|
||||
|> Enum.filter(fn user -> User.ap_enabled?(user) end)
|
||||
|> Enum.map(fn %{info: %{"source_data" => data}} ->
|
||||
|> Enum.map(fn %{info: %{source_data: data}} ->
|
||||
(is_map(data["endpoints"]) && Map.get(data["endpoints"], "sharedInbox")) || data["inbox"]
|
||||
end)
|
||||
|> Enum.uniq()
|
||||
|
|
@ -764,7 +769,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
Logger.info("Fetching #{id} via AP")
|
||||
|
||||
with true <- String.starts_with?(id, "http"),
|
||||
{:ok, %{body: body, status_code: code}} when code in 200..299 <-
|
||||
{:ok, %{body: body, status: code}} when code in 200..299 <-
|
||||
@httpoison.get(
|
||||
id,
|
||||
[Accept: "application/activity+json"],
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
|
|||
|
||||
defp check_media_removal(
|
||||
%{host: actor_host} = _actor_info,
|
||||
%{"type" => "Create", "object" => %{"attachement" => child_attachment}} = object
|
||||
%{"type" => "Create", "object" => %{"attachment" => child_attachment}} = object
|
||||
)
|
||||
when length(child_attachment) > 0 do
|
||||
object =
|
||||
|
|
|
|||
|
|
@ -447,7 +447,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
update_data =
|
||||
new_user_data
|
||||
|> Map.take([:name, :bio, :avatar])
|
||||
|> Map.put(:info, Map.merge(actor.info, %{"banner" => banner, "locked" => locked}))
|
||||
|> Map.put(:info, %{"banner" => banner, "locked" => locked})
|
||||
|
||||
actor
|
||||
|> User.upgrade_changeset(update_data)
|
||||
|
|
@ -850,10 +850,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
def upgrade_user_from_ap_id(ap_id, async \\ true) do
|
||||
with %User{local: false} = user <- User.get_by_ap_id(ap_id),
|
||||
{:ok, data} <- ActivityPub.fetch_and_prepare_user_from_ap_id(ap_id) do
|
||||
data =
|
||||
data
|
||||
|> Map.put(:info, Map.merge(user.info, data[:info]))
|
||||
|
||||
already_ap = User.ap_enabled?(user)
|
||||
|
||||
{:ok, user} =
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
# the instance itself is not a Person, but instead an Application
|
||||
def render("user.json", %{user: %{nickname: nil} = user}) do
|
||||
{:ok, user} = WebFinger.ensure_keys_present(user)
|
||||
{:ok, _, public_key} = Salmon.keys_from_pem(user.info["keys"])
|
||||
{:ok, _, public_key} = Salmon.keys_from_pem(user.info.keys)
|
||||
public_key = :public_key.pem_entry_encode(:SubjectPublicKeyInfo, public_key)
|
||||
public_key = :public_key.pem_encode([public_key])
|
||||
|
||||
|
|
@ -40,7 +40,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
|
||||
def render("user.json", %{user: user}) do
|
||||
{:ok, user} = WebFinger.ensure_keys_present(user)
|
||||
{:ok, _, public_key} = Salmon.keys_from_pem(user.info["keys"])
|
||||
{:ok, _, public_key} = Salmon.keys_from_pem(user.info.keys)
|
||||
public_key = :public_key.pem_entry_encode(:SubjectPublicKeyInfo, public_key)
|
||||
public_key = :public_key.pem_encode([public_key])
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
"name" => user.name,
|
||||
"summary" => user.bio,
|
||||
"url" => user.ap_id,
|
||||
"manuallyApprovesFollowers" => user.info["locked"] || false,
|
||||
"manuallyApprovesFollowers" => user.info.locked,
|
||||
"publicKey" => %{
|
||||
"id" => "#{user.ap_id}#main-key",
|
||||
"owner" => user.ap_id,
|
||||
|
|
@ -72,7 +72,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
"type" => "Image",
|
||||
"url" => User.banner_url(user)
|
||||
},
|
||||
"tag" => user.info["source_data"]["tag"] || []
|
||||
"tag" => user.info.source_data["tag"] || []
|
||||
}
|
||||
|> Map.merge(Utils.make_json_ld_header())
|
||||
end
|
||||
|
|
@ -82,7 +82,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
query = from(user in query, select: [:ap_id])
|
||||
following = Repo.all(query)
|
||||
|
||||
collection(following, "#{user.ap_id}/following", page)
|
||||
collection(following, "#{user.ap_id}/following", page, !user.info.hide_network)
|
||||
|> Map.merge(Utils.make_json_ld_header())
|
||||
end
|
||||
|
||||
|
|
@ -95,7 +95,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
"id" => "#{user.ap_id}/following",
|
||||
"type" => "OrderedCollection",
|
||||
"totalItems" => length(following),
|
||||
"first" => collection(following, "#{user.ap_id}/following", 1)
|
||||
"first" => collection(following, "#{user.ap_id}/following", 1, !user.info.hide_network)
|
||||
}
|
||||
|> Map.merge(Utils.make_json_ld_header())
|
||||
end
|
||||
|
|
@ -105,7 +105,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
query = from(user in query, select: [:ap_id])
|
||||
followers = Repo.all(query)
|
||||
|
||||
collection(followers, "#{user.ap_id}/followers", page)
|
||||
collection(followers, "#{user.ap_id}/followers", page, !user.info.hide_network)
|
||||
|> Map.merge(Utils.make_json_ld_header())
|
||||
end
|
||||
|
||||
|
|
@ -118,7 +118,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
"id" => "#{user.ap_id}/followers",
|
||||
"type" => "OrderedCollection",
|
||||
"totalItems" => length(followers),
|
||||
"first" => collection(followers, "#{user.ap_id}/followers", 1)
|
||||
"first" => collection(followers, "#{user.ap_id}/followers", 1, !user.info.hide_network)
|
||||
}
|
||||
|> Map.merge(Utils.make_json_ld_header())
|
||||
end
|
||||
|
|
@ -172,7 +172,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
end
|
||||
end
|
||||
|
||||
def collection(collection, iri, page, total \\ nil) do
|
||||
def collection(collection, iri, page, show_items \\ true, total \\ nil) do
|
||||
offset = (page - 1) * 10
|
||||
items = Enum.slice(collection, offset, 10)
|
||||
items = Enum.map(items, fn user -> user.ap_id end)
|
||||
|
|
@ -183,7 +183,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
"type" => "OrderedCollectionPage",
|
||||
"partOf" => iri,
|
||||
"totalItems" => total,
|
||||
"orderedItems" => items
|
||||
"orderedItems" => if(show_items, do: items, else: [])
|
||||
}
|
||||
|
||||
if offset < total do
|
||||
|
|
|
|||
|
|
@ -45,21 +45,29 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
user = User.get_by_nickname(nickname)
|
||||
|
||||
info =
|
||||
user.info
|
||||
%{}
|
||||
|> Map.put("is_" <> permission_group, true)
|
||||
|
||||
cng = User.info_changeset(user, %{info: info})
|
||||
info_cng = User.Info.admin_api_update(user.info, info)
|
||||
|
||||
cng =
|
||||
Ecto.Changeset.change(user)
|
||||
|> Ecto.Changeset.put_embed(:info, info_cng)
|
||||
|
||||
{:ok, user} = User.update_and_set_cache(cng)
|
||||
|
||||
conn
|
||||
|> json(user.info)
|
||||
|> json(info)
|
||||
end
|
||||
|
||||
def right_get(conn, %{"nickname" => nickname}) do
|
||||
user = User.get_by_nickname(nickname)
|
||||
|
||||
conn
|
||||
|> json(user.info)
|
||||
|> json(%{
|
||||
is_moderator: user.info.is_moderator,
|
||||
is_admin: user.info.is_admin
|
||||
})
|
||||
end
|
||||
|
||||
def right_add(conn, _) do
|
||||
|
|
@ -84,14 +92,19 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
user = User.get_by_nickname(nickname)
|
||||
|
||||
info =
|
||||
user.info
|
||||
%{}
|
||||
|> Map.put("is_" <> permission_group, false)
|
||||
|
||||
cng = User.info_changeset(user, %{info: info})
|
||||
info_cng = User.Info.admin_api_update(user.info, info)
|
||||
|
||||
cng =
|
||||
Ecto.Changeset.change(user)
|
||||
|> Ecto.Changeset.put_embed(:info, info_cng)
|
||||
|
||||
{:ok, user} = User.update_and_set_cache(cng)
|
||||
|
||||
conn
|
||||
|> json(user.info)
|
||||
|> json(info)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
def delete(activity_id, user) do
|
||||
with %Activity{data: %{"object" => %{"id" => object_id}}} <- Repo.get(Activity, activity_id),
|
||||
%Object{} = object <- Object.normalize(object_id),
|
||||
true <- user.info["is_moderator"] || user.ap_id == object.data["actor"],
|
||||
true <- user.info.is_moderator || user.ap_id == object.data["actor"],
|
||||
{:ok, delete} <- ActivityPub.delete(object) do
|
||||
{:ok, delete}
|
||||
end
|
||||
|
|
@ -135,12 +135,13 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
end
|
||||
end
|
||||
|
||||
# Updates the emojis for a user based on their profile
|
||||
def update(user) do
|
||||
user =
|
||||
with emoji <- emoji_from_profile(user),
|
||||
source_data <- (user.info["source_data"] || %{}) |> Map.put("tag", emoji),
|
||||
new_info <- Map.put(user.info, "source_data", source_data),
|
||||
change <- User.info_changeset(user, %{info: new_info}),
|
||||
source_data <- (user.info.source_data || %{}) |> Map.put("tag", emoji),
|
||||
info_cng <- Pleroma.User.Info.set_source_data(user.info, source_data),
|
||||
change <- Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_cng),
|
||||
{:ok, user} <- User.update_and_set_cache(change) do
|
||||
user
|
||||
else
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ defmodule Pleroma.Web.Endpoint do
|
|||
plug(CORSPlug)
|
||||
plug(Pleroma.Plugs.HTTPSecurityPlug)
|
||||
|
||||
plug(Plug.Static, at: "/media", from: Pleroma.Uploaders.Local.upload_path(), gzip: false)
|
||||
plug(Pleroma.Plugs.UploadedMedia)
|
||||
|
||||
plug(
|
||||
Plug.Static,
|
||||
|
|
|
|||
|
|
@ -17,7 +17,15 @@ defmodule Pleroma.Web.Federator.RetryQueue do
|
|||
end
|
||||
|
||||
def start_link() do
|
||||
GenServer.start_link(__MODULE__, %{delivered: 0, dropped: 0}, name: __MODULE__)
|
||||
enabled = Pleroma.Config.get([:retry_queue, :enabled], false)
|
||||
|
||||
if enabled do
|
||||
Logger.info("Starting retry queue")
|
||||
GenServer.start_link(__MODULE__, %{delivered: 0, dropped: 0}, name: __MODULE__)
|
||||
else
|
||||
Logger.info("Retry queue disabled")
|
||||
:ignore
|
||||
end
|
||||
end
|
||||
|
||||
def enqueue(data, transport, retries \\ 0) do
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ defmodule Pleroma.Web.HTTPSignatures do
|
|||
end
|
||||
|
||||
def sign(user, headers) do
|
||||
with {:ok, %{info: %{"keys" => keys}}} <- Pleroma.Web.WebFinger.ensure_keys_present(user),
|
||||
with {:ok, %{info: %{keys: keys}}} <- Pleroma.Web.WebFinger.ensure_keys_present(user),
|
||||
{:ok, private_key, _} = Pleroma.Web.Salmon.keys_from_pem(keys) do
|
||||
sigstring = build_signing_string(headers, Map.keys(headers))
|
||||
|
||||
|
|
|
|||
|
|
@ -32,75 +32,55 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
end
|
||||
end
|
||||
|
||||
defp add_if_present(
|
||||
map,
|
||||
params,
|
||||
params_field,
|
||||
map_field,
|
||||
value_function \\ fn x -> {:ok, x} end
|
||||
) do
|
||||
if Map.has_key?(params, params_field) do
|
||||
case value_function.(params[params_field]) do
|
||||
{:ok, new_value} -> Map.put(map, map_field, new_value)
|
||||
:error -> map
|
||||
end
|
||||
else
|
||||
map
|
||||
end
|
||||
end
|
||||
|
||||
def update_credentials(%{assigns: %{user: user}} = conn, params) do
|
||||
original_user = user
|
||||
|
||||
avatar_upload_limit =
|
||||
Application.get_env(:pleroma, :instance)
|
||||
|> Keyword.fetch(:avatar_upload_limit)
|
||||
|
||||
banner_upload_limit =
|
||||
Application.get_env(:pleroma, :instance)
|
||||
|> Keyword.fetch(:banner_upload_limit)
|
||||
|
||||
params =
|
||||
if bio = params["note"] do
|
||||
Map.put(params, "bio", bio)
|
||||
else
|
||||
params
|
||||
end
|
||||
|
||||
params =
|
||||
if name = params["display_name"] do
|
||||
Map.put(params, "name", name)
|
||||
else
|
||||
params
|
||||
end
|
||||
|
||||
user =
|
||||
if avatar = params["avatar"] do
|
||||
with %Plug.Upload{} <- avatar,
|
||||
{:ok, object} <- ActivityPub.upload(avatar, avatar_upload_limit),
|
||||
change = Ecto.Changeset.change(user, %{avatar: object.data}),
|
||||
{:ok, user} = User.update_and_set_cache(change) do
|
||||
user
|
||||
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, "avatar", :avatar, fn value ->
|
||||
with %Plug.Upload{} <- value,
|
||||
{:ok, object} <- ActivityPub.upload(value, type: :avatar) do
|
||||
{:ok, object.data}
|
||||
else
|
||||
_e -> user
|
||||
_ -> :error
|
||||
end
|
||||
else
|
||||
user
|
||||
end
|
||||
end)
|
||||
|
||||
user =
|
||||
if banner = params["header"] do
|
||||
with %Plug.Upload{} <- banner,
|
||||
{:ok, object} <- ActivityPub.upload(banner, banner_upload_limit),
|
||||
new_info <- Map.put(user.info, "banner", object.data),
|
||||
change <- User.info_changeset(user, %{info: new_info}),
|
||||
{:ok, user} <- User.update_and_set_cache(change) do
|
||||
user
|
||||
info_params =
|
||||
%{}
|
||||
|> add_if_present(params, "locked", :locked, fn value -> {:ok, value == "true"} end)
|
||||
|> add_if_present(params, "header", :banner, fn value ->
|
||||
with %Plug.Upload{} <- value,
|
||||
{:ok, object} <- ActivityPub.upload(value, type: :banner) do
|
||||
{:ok, object.data}
|
||||
else
|
||||
_e -> user
|
||||
_ -> :error
|
||||
end
|
||||
else
|
||||
user
|
||||
end
|
||||
end)
|
||||
|
||||
user =
|
||||
if locked = params["locked"] do
|
||||
with locked <- locked == "true",
|
||||
new_info <- Map.put(user.info, "locked", locked),
|
||||
change <- User.info_changeset(user, %{info: new_info}),
|
||||
{:ok, user} <- User.update_and_set_cache(change) do
|
||||
user
|
||||
else
|
||||
_e -> user
|
||||
end
|
||||
else
|
||||
user
|
||||
end
|
||||
info_cng = User.Info.mastodon_profile_update(user.info, info_params)
|
||||
|
||||
with changeset <- User.update_changeset(user, params),
|
||||
with changeset <- User.update_changeset(user, user_params),
|
||||
changeset <- Ecto.Changeset.put_embed(changeset, :info, info_cng),
|
||||
{:ok, user} <- User.update_and_set_cache(changeset) do
|
||||
if original_user != user do
|
||||
CommonAPI.update(user)
|
||||
|
|
@ -453,40 +433,31 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
|> json([])
|
||||
end
|
||||
|
||||
def update_media(%{assigns: %{user: _}} = conn, data) do
|
||||
def update_media(%{assigns: %{user: user}} = conn, data) do
|
||||
with %Object{} = object <- Repo.get(Object, data["id"]),
|
||||
true <- Object.authorize_mutation(object, user),
|
||||
true <- is_binary(data["description"]),
|
||||
description <- data["description"] do
|
||||
new_data = %{object.data | "name" => description}
|
||||
|
||||
change = Object.change(object, %{data: new_data})
|
||||
{:ok, _} = Repo.update(change)
|
||||
{:ok, _} =
|
||||
object
|
||||
|> Object.change(%{data: new_data})
|
||||
|> Repo.update()
|
||||
|
||||
data =
|
||||
new_data
|
||||
|> Map.put("id", object.id)
|
||||
|
||||
render(conn, StatusView, "attachment.json", %{attachment: data})
|
||||
attachment_data = Map.put(new_data, "id", object.id)
|
||||
render(conn, StatusView, "attachment.json", %{attachment: attachment_data})
|
||||
end
|
||||
end
|
||||
|
||||
def upload(%{assigns: %{user: _}} = conn, %{"file" => file} = data) do
|
||||
with {:ok, object} <- ActivityPub.upload(file) do
|
||||
objdata =
|
||||
if Map.has_key?(data, "description") do
|
||||
Map.put(object.data, "name", data["description"])
|
||||
else
|
||||
object.data
|
||||
end
|
||||
|
||||
change = Object.change(object, %{data: objdata})
|
||||
{:ok, object} = Repo.update(change)
|
||||
|
||||
objdata =
|
||||
objdata
|
||||
|> Map.put("id", object.id)
|
||||
|
||||
render(conn, StatusView, "attachment.json", %{attachment: objdata})
|
||||
def upload(%{assigns: %{user: user}} = conn, %{"file" => file} = data) do
|
||||
with {:ok, object} <-
|
||||
ActivityPub.upload(file,
|
||||
actor: User.ap_id(user),
|
||||
description: Map.get(data, "description")
|
||||
) do
|
||||
attachment_data = Map.put(object.data, "id", object.id)
|
||||
render(conn, StatusView, "attachment.json", %{attachment: attachment_data})
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -529,17 +500,30 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
|> render(StatusView, "index.json", %{activities: activities, for: user, as: :activity})
|
||||
end
|
||||
|
||||
# TODO: Pagination
|
||||
def followers(conn, %{"id" => id}) do
|
||||
def followers(%{assigns: %{user: for_user}} = conn, %{"id" => id}) do
|
||||
with %User{} = user <- Repo.get(User, id),
|
||||
{:ok, followers} <- User.get_followers(user) do
|
||||
followers =
|
||||
cond do
|
||||
for_user && user.id == for_user.id -> followers
|
||||
user.info.hide_network -> []
|
||||
true -> followers
|
||||
end
|
||||
|
||||
render(conn, AccountView, "accounts.json", %{users: followers, as: :user})
|
||||
end
|
||||
end
|
||||
|
||||
def following(conn, %{"id" => id}) do
|
||||
def following(%{assigns: %{user: for_user}} = conn, %{"id" => id}) do
|
||||
with %User{} = user <- Repo.get(User, id),
|
||||
{:ok, followers} <- User.get_friends(user) do
|
||||
followers =
|
||||
cond do
|
||||
for_user && user.id == for_user.id -> followers
|
||||
user.info.hide_network -> []
|
||||
true -> followers
|
||||
end
|
||||
|
||||
render(conn, AccountView, "accounts.json", %{users: followers, as: :user})
|
||||
end
|
||||
end
|
||||
|
|
@ -659,7 +643,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
|
||||
# TODO: Use proper query
|
||||
def blocks(%{assigns: %{user: user}} = conn, _) do
|
||||
with blocked_users <- user.info["blocks"] || [],
|
||||
with blocked_users <- user.info.blocks || [],
|
||||
accounts <- Enum.map(blocked_users, fn ap_id -> User.get_cached_by_ap_id(ap_id) end) do
|
||||
res = AccountView.render("accounts.json", users: accounts, for: user, as: :user)
|
||||
json(conn, res)
|
||||
|
|
@ -667,7 +651,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
end
|
||||
|
||||
def domain_blocks(%{assigns: %{user: %{info: info}}} = conn, _) do
|
||||
json(conn, info["domain_blocks"] || [])
|
||||
json(conn, info.domain_blocks || [])
|
||||
end
|
||||
|
||||
def block_domain(%{assigns: %{user: blocker}} = conn, %{"domain" => domain}) do
|
||||
|
|
@ -915,11 +899,11 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
max_toot_chars: limit
|
||||
},
|
||||
rights: %{
|
||||
delete_others_notice: !!user.info["is_moderator"]
|
||||
delete_others_notice: !!user.info.is_moderator
|
||||
},
|
||||
compose: %{
|
||||
me: "#{user.id}",
|
||||
default_privacy: user.info["default_scope"] || "public",
|
||||
default_privacy: user.info.default_scope,
|
||||
default_sensitive: false
|
||||
},
|
||||
media_attachments: %{
|
||||
|
|
@ -939,7 +923,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
]
|
||||
},
|
||||
settings:
|
||||
Map.get(user.info, "settings") ||
|
||||
Map.get(user.info, :settings) ||
|
||||
%{
|
||||
onboarded: true,
|
||||
home: %{
|
||||
|
|
@ -1224,7 +1208,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
user = user.nickname
|
||||
url = String.replace(api, "{{host}}", host) |> String.replace("{{user}}", user)
|
||||
|
||||
with {:ok, %{status_code: 200, body: body}} <-
|
||||
with {:ok, %{status: 200, body: body}} <-
|
||||
@httpoison.get(url, [], timeout: timeout, recv_timeout: timeout),
|
||||
{:ok, data} <- Jason.decode(body) do
|
||||
data2 =
|
||||
|
|
|
|||
|
|
@ -14,10 +14,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
|||
image = User.avatar_url(user) |> MediaProxy.url()
|
||||
header = User.banner_url(user) |> MediaProxy.url()
|
||||
user_info = User.user_info(user)
|
||||
bot = (user.info["source_data"]["type"] || "Person") in ["Application", "Service"]
|
||||
bot = (user.info.source_data["type"] || "Person") in ["Application", "Service"]
|
||||
|
||||
emojis =
|
||||
(user.info["source_data"]["tag"] || [])
|
||||
(user.info.source_data["tag"] || [])
|
||||
|> Enum.filter(fn %{"type" => t} -> t == "Emoji" end)
|
||||
|> Enum.map(fn %{"icon" => %{"url" => url}, "name" => name} ->
|
||||
%{
|
||||
|
|
@ -29,7 +29,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
|||
end)
|
||||
|
||||
fields =
|
||||
(user.info["source_data"]["attachment"] || [])
|
||||
(user.info.source_data["attachment"] || [])
|
||||
|> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end)
|
||||
|> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,135 +1,34 @@
|
|||
defmodule Pleroma.Web.MediaProxy.MediaProxyController do
|
||||
use Pleroma.Web, :controller
|
||||
require Logger
|
||||
alias Pleroma.{Web.MediaProxy, ReverseProxy}
|
||||
|
||||
@httpoison Application.get_env(:pleroma, :httpoison)
|
||||
@default_proxy_opts [max_body_length: 25 * 1_048_576]
|
||||
|
||||
@max_body_length 25 * 1_048_576
|
||||
|
||||
@cache_control %{
|
||||
default: "public, max-age=1209600",
|
||||
error: "public, must-revalidate, max-age=160"
|
||||
}
|
||||
|
||||
# Content-types that will not be returned as content-disposition attachments
|
||||
# Override with :media_proxy, :safe_content_types in the configuration
|
||||
@safe_content_types [
|
||||
"image/gif",
|
||||
"image/jpeg",
|
||||
"image/jpg",
|
||||
"image/png",
|
||||
"image/svg+xml",
|
||||
"audio/mpeg",
|
||||
"audio/mp3",
|
||||
"video/webm",
|
||||
"video/mp4"
|
||||
]
|
||||
|
||||
def remote(conn, params = %{"sig" => sig, "url" => url}) do
|
||||
config = Application.get_env(:pleroma, :media_proxy, [])
|
||||
|
||||
with true <- Keyword.get(config, :enabled, false),
|
||||
{:ok, url} <- Pleroma.Web.MediaProxy.decode_url(sig, url),
|
||||
def remote(conn, params = %{"sig" => sig64, "url" => url64}) do
|
||||
with config <- Pleroma.Config.get([:media_proxy], []),
|
||||
true <- Keyword.get(config, :enabled, false),
|
||||
{:ok, url} <- MediaProxy.decode_url(sig64, url64),
|
||||
filename <- Path.basename(URI.parse(url).path),
|
||||
true <-
|
||||
if(Map.get(params, "filename"),
|
||||
do: filename == Path.basename(conn.request_path),
|
||||
else: true
|
||||
),
|
||||
{:ok, content_type, body} <- proxy_request(url),
|
||||
safe_content_type <-
|
||||
Enum.member?(
|
||||
Keyword.get(config, :safe_content_types, @safe_content_types),
|
||||
content_type
|
||||
) do
|
||||
conn
|
||||
|> put_resp_content_type(content_type)
|
||||
|> set_cache_header(:default)
|
||||
|> put_resp_header(
|
||||
"content-security-policy",
|
||||
"default-src 'none'; style-src 'unsafe-inline'; media-src data:; img-src 'self' data:"
|
||||
)
|
||||
|> put_resp_header("x-xss-protection", "1; mode=block")
|
||||
|> put_resp_header("x-content-type-options", "nosniff")
|
||||
|> put_attachement_header(safe_content_type, filename)
|
||||
|> send_resp(200, body)
|
||||
:ok <- filename_matches(Map.has_key?(params, "filename"), conn.request_path, url) do
|
||||
ReverseProxy.call(conn, url, Keyword.get(config, :proxy_opts, @default_proxy_opts))
|
||||
else
|
||||
false ->
|
||||
send_error(conn, 404)
|
||||
send_resp(conn, 404, Plug.Conn.Status.reason_phrase(404))
|
||||
|
||||
{:error, :invalid_signature} ->
|
||||
send_error(conn, 403)
|
||||
send_resp(conn, 403, Plug.Conn.Status.reason_phrase(403))
|
||||
|
||||
{:error, {:http, _, url}} ->
|
||||
redirect_or_error(conn, url, Keyword.get(config, :redirect_on_failure, true))
|
||||
{:wrong_filename, filename} ->
|
||||
redirect(conn, external: MediaProxy.build_url(sig64, url64, filename))
|
||||
end
|
||||
end
|
||||
|
||||
defp proxy_request(link) do
|
||||
headers = [
|
||||
{"user-agent",
|
||||
"Pleroma/MediaProxy; #{Pleroma.Web.base_url()} <#{
|
||||
Application.get_env(:pleroma, :instance)[:email]
|
||||
}>"}
|
||||
]
|
||||
def filename_matches(has_filename, path, url) do
|
||||
filename = MediaProxy.filename(url)
|
||||
|
||||
options =
|
||||
@httpoison.process_request_options([:insecure, {:follow_redirect, true}]) ++
|
||||
[{:pool, :default}]
|
||||
|
||||
with {:ok, 200, headers, client} <- :hackney.request(:get, link, headers, "", options),
|
||||
headers = Enum.into(headers, Map.new()),
|
||||
{:ok, body} <- proxy_request_body(client),
|
||||
content_type <- proxy_request_content_type(headers, body) do
|
||||
{:ok, content_type, body}
|
||||
else
|
||||
{:ok, status, _, _} ->
|
||||
Logger.warn("MediaProxy: request failed, status #{status}, link: #{link}")
|
||||
{:error, {:http, :bad_status, link}}
|
||||
|
||||
{:error, error} ->
|
||||
Logger.warn("MediaProxy: request failed, error #{inspect(error)}, link: #{link}")
|
||||
{:error, {:http, error, link}}
|
||||
cond do
|
||||
has_filename && filename && Path.basename(path) != filename -> {:wrong_filename, filename}
|
||||
true -> :ok
|
||||
end
|
||||
end
|
||||
|
||||
defp set_cache_header(conn, key) do
|
||||
Plug.Conn.put_resp_header(conn, "cache-control", @cache_control[key])
|
||||
end
|
||||
|
||||
defp redirect_or_error(conn, url, true), do: redirect(conn, external: url)
|
||||
defp redirect_or_error(conn, url, _), do: send_error(conn, 502, "Media proxy error: " <> url)
|
||||
|
||||
defp send_error(conn, code, body \\ "") do
|
||||
conn
|
||||
|> set_cache_header(:error)
|
||||
|> send_resp(code, body)
|
||||
end
|
||||
|
||||
defp proxy_request_body(client), do: proxy_request_body(client, <<>>)
|
||||
|
||||
defp proxy_request_body(client, body) when byte_size(body) < @max_body_length do
|
||||
case :hackney.stream_body(client) do
|
||||
{:ok, data} -> proxy_request_body(client, <<body::binary, data::binary>>)
|
||||
:done -> {:ok, body}
|
||||
{:error, reason} -> {:error, reason}
|
||||
end
|
||||
end
|
||||
|
||||
defp proxy_request_body(client, _) do
|
||||
:hackney.close(client)
|
||||
{:error, :body_too_large}
|
||||
end
|
||||
|
||||
# TODO: the body is passed here as well because some hosts do not provide a content-type.
|
||||
# At some point we may want to use magic numbers to discover the content-type and reply a proper one.
|
||||
defp proxy_request_content_type(headers, _body) do
|
||||
headers["Content-Type"] || headers["content-type"] || "application/octet-stream"
|
||||
end
|
||||
|
||||
defp put_attachement_header(conn, true, _), do: conn
|
||||
|
||||
defp put_attachement_header(conn, false, filename) do
|
||||
put_resp_header(conn, "content-disposition", "attachment; filename='#{filename}'")
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -17,10 +17,8 @@ defmodule Pleroma.Web.MediaProxy do
|
|||
base64 = Base.url_encode64(url, @base64_opts)
|
||||
sig = :crypto.hmac(:sha, secret, base64)
|
||||
sig64 = sig |> Base.url_encode64(@base64_opts)
|
||||
filename = if path = URI.parse(url).path, do: "/" <> Path.basename(path), else: ""
|
||||
|
||||
Keyword.get(config, :base_url, Pleroma.Web.base_url()) <>
|
||||
"/proxy/#{sig64}/#{base64}#{filename}"
|
||||
build_url(sig64, base64, filename(url))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -35,4 +33,20 @@ defmodule Pleroma.Web.MediaProxy do
|
|||
{:error, :invalid_signature}
|
||||
end
|
||||
end
|
||||
|
||||
def filename(url_or_path) do
|
||||
if path = URI.parse(url_or_path).path, do: Path.basename(path)
|
||||
end
|
||||
|
||||
def build_url(sig_base64, url_base64, filename \\ nil) do
|
||||
[
|
||||
Pleroma.Config.get([:media_proxy, :base_url], Pleroma.Web.base_url()),
|
||||
"proxy",
|
||||
sig_base64,
|
||||
url_base64,
|
||||
filename
|
||||
]
|
||||
|> Enum.filter(fn value -> value end)
|
||||
|> Path.join()
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -226,25 +226,21 @@ defmodule Pleroma.Web.OStatus do
|
|||
old_data = %{
|
||||
avatar: user.avatar,
|
||||
bio: user.bio,
|
||||
name: user.name,
|
||||
info: user.info
|
||||
name: user.name
|
||||
}
|
||||
|
||||
with false <- user.local,
|
||||
avatar <- make_avatar_object(doc),
|
||||
bio <- string_from_xpath("//author[1]/summary", doc),
|
||||
name <- string_from_xpath("//author[1]/poco:displayName", doc),
|
||||
info <-
|
||||
Map.put(user.info, "banner", make_avatar_object(doc, "header") || user.info["banner"]),
|
||||
new_data <- %{
|
||||
avatar: avatar || old_data.avatar,
|
||||
name: name || old_data.name,
|
||||
bio: bio || old_data.bio,
|
||||
info: info || old_data.info
|
||||
bio: bio || old_data.bio
|
||||
},
|
||||
false <- new_data == old_data do
|
||||
change = Ecto.Changeset.change(user, new_data)
|
||||
Repo.update(change)
|
||||
User.update_and_set_cache(change)
|
||||
else
|
||||
_ ->
|
||||
{:ok, user}
|
||||
|
|
@ -350,13 +346,15 @@ defmodule Pleroma.Web.OStatus do
|
|||
|
||||
def fetch_activity_from_atom_url(url) do
|
||||
with true <- String.starts_with?(url, "http"),
|
||||
{:ok, %{body: body, status_code: code}} when code in 200..299 <-
|
||||
{:ok, %{body: body, status: code}} when code in 200..299 <-
|
||||
@httpoison.get(
|
||||
url,
|
||||
[Accept: "application/atom+xml"],
|
||||
follow_redirect: true,
|
||||
timeout: 10000,
|
||||
recv_timeout: 20000
|
||||
adapter: [
|
||||
timeout: 10000,
|
||||
recv_timeout: 20000
|
||||
]
|
||||
) do
|
||||
Logger.debug("Got document from #{url}, handling...")
|
||||
handle_incoming(body)
|
||||
|
|
|
|||
|
|
@ -302,12 +302,6 @@ defmodule Pleroma.Web.Router do
|
|||
post("/account/update_profile_banner", TwitterAPI.Controller, :update_banner)
|
||||
post("/qvitter/update_background_image", TwitterAPI.Controller, :update_background)
|
||||
|
||||
post(
|
||||
"/account/most_recent_notification",
|
||||
TwitterAPI.Controller,
|
||||
:update_most_recent_notification
|
||||
)
|
||||
|
||||
get("/statuses/home_timeline", TwitterAPI.Controller, :friends_timeline)
|
||||
get("/statuses/friends_timeline", TwitterAPI.Controller, :friends_timeline)
|
||||
get("/statuses/mentions", TwitterAPI.Controller, :mentions_timeline)
|
||||
|
|
@ -335,6 +329,7 @@ defmodule Pleroma.Web.Router do
|
|||
|
||||
post("/statusnet/media/upload", TwitterAPI.Controller, :upload)
|
||||
post("/media/upload", TwitterAPI.Controller, :upload_json)
|
||||
post("/media/metadata/create", TwitterAPI.Controller, :update_media)
|
||||
|
||||
post("/favorites/create/:id", TwitterAPI.Controller, :favorite)
|
||||
post("/favorites/create", TwitterAPI.Controller, :favorite)
|
||||
|
|
|
|||
|
|
@ -157,15 +157,17 @@ defmodule Pleroma.Web.Salmon do
|
|||
|> Enum.filter(fn user -> user && !user.local end)
|
||||
end
|
||||
|
||||
defp send_to_user(%{info: %{"salmon" => salmon}}, feed, poster) do
|
||||
with {:ok, %{status_code: code}} <-
|
||||
defp send_to_user(%{info: %{salmon: salmon}}, feed, poster) do
|
||||
with {:ok, %{status: code}} <-
|
||||
poster.(
|
||||
salmon,
|
||||
feed,
|
||||
[{"Content-Type", "application/magic-envelope+xml"}],
|
||||
timeout: 10000,
|
||||
recv_timeout: 20000,
|
||||
hackney: [pool: :default]
|
||||
adapter: [
|
||||
timeout: 10000,
|
||||
recv_timeout: 20000,
|
||||
pool: :default
|
||||
]
|
||||
) do
|
||||
Logger.debug(fn -> "Pushed to #{salmon}, code #{code}" end)
|
||||
else
|
||||
|
|
@ -185,7 +187,7 @@ defmodule Pleroma.Web.Salmon do
|
|||
]
|
||||
def publish(user, activity, poster \\ &@httpoison.post/4)
|
||||
|
||||
def publish(%{info: %{"keys" => keys}} = user, %{data: %{"type" => type}} = activity, poster)
|
||||
def publish(%{info: %{keys: keys}} = user, %{data: %{"type" => type}} = activity, poster)
|
||||
when type in @supported_activities do
|
||||
feed = ActivityRepresenter.to_simple_form(activity, user, true)
|
||||
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ defmodule Pleroma.Web.Streamer do
|
|||
# Get the current user so we have up-to-date blocks etc.
|
||||
if socket.assigns[:user] do
|
||||
user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id)
|
||||
blocks = user.info["blocks"] || []
|
||||
blocks = user.info.blocks || []
|
||||
|
||||
parent = Object.normalize(item.data["object"])
|
||||
|
||||
|
|
@ -206,7 +206,7 @@ defmodule Pleroma.Web.Streamer do
|
|||
# Get the current user so we have up-to-date blocks etc.
|
||||
if socket.assigns[:user] do
|
||||
user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id)
|
||||
blocks = user.info["blocks"] || []
|
||||
blocks = user.info.blocks || []
|
||||
|
||||
unless item.actor in blocks do
|
||||
send(socket.transport_pid, {:text, represent_update(item, user)})
|
||||
|
|
|
|||
|
|
@ -93,11 +93,11 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
|
|||
end
|
||||
end
|
||||
|
||||
def upload(%Plug.Upload{} = file, format \\ "xml") do
|
||||
{:ok, object} = ActivityPub.upload(file)
|
||||
def upload(%Plug.Upload{} = file, %User{} = user, format \\ "xml") do
|
||||
{:ok, object} = ActivityPub.upload(file, actor: User.ap_id(user))
|
||||
|
||||
url = List.first(object.data["url"])
|
||||
href = url["href"] |> MediaProxy.url()
|
||||
href = url["href"]
|
||||
type = url["mediaType"]
|
||||
|
||||
case format do
|
||||
|
|
@ -132,7 +132,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
|
|||
params = %{
|
||||
nickname: params["nickname"],
|
||||
name: params["fullname"],
|
||||
bio: params["bio"],
|
||||
bio: User.parse_bio(params["bio"]),
|
||||
email: params["email"],
|
||||
password: params["password"],
|
||||
password_confirmation: params["confirm"]
|
||||
|
|
@ -148,7 +148,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
|
|||
|
||||
cond do
|
||||
registrations_open || (!is_nil(token) && !token.used) ->
|
||||
changeset = User.register_changeset(%User{}, params)
|
||||
changeset = User.register_changeset(%User{info: %{}}, params)
|
||||
|
||||
with {:ok, user} <- Repo.insert(changeset) do
|
||||
!registrations_open && UserInviteToken.mark_as_used(token.token)
|
||||
|
|
@ -279,14 +279,6 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
|
|||
|
||||
def get_external_profile(for_user, uri) do
|
||||
with %User{} = user <- User.get_or_fetch(uri) do
|
||||
spawn(fn ->
|
||||
with url <- user.info["topic"],
|
||||
{:ok, %{body: body}} <-
|
||||
@httpoison.get(url, [], follow_redirect: true, timeout: 10000, recv_timeout: 20000) do
|
||||
OStatus.handle_incoming(body)
|
||||
end
|
||||
end)
|
||||
|
||||
{:ok, UserView.render("show.json", %{user: user, for: for_user})}
|
||||
else
|
||||
_e ->
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
|
|||
alias Pleroma.Web.TwitterAPI.{TwitterAPI, UserView, ActivityView, NotificationView}
|
||||
alias Pleroma.Web.CommonAPI
|
||||
alias Pleroma.Web.CommonAPI.Utils, as: CommonUtils
|
||||
alias Pleroma.{Repo, Activity, User, Notification}
|
||||
alias Pleroma.{Repo, Activity, Object, User, Notification}
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
alias Pleroma.Web.ActivityPub.Utils
|
||||
alias Ecto.Changeset
|
||||
|
|
@ -226,16 +226,51 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
|
|||
end
|
||||
end
|
||||
|
||||
def upload(conn, %{"media" => media}) do
|
||||
response = TwitterAPI.upload(media)
|
||||
@doc """
|
||||
Updates metadata of uploaded media object.
|
||||
Derived from [Twitter API endpoint](https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-metadata-create).
|
||||
"""
|
||||
def update_media(%{assigns: %{user: user}} = conn, %{"media_id" => id} = data) do
|
||||
object = Repo.get(Object, id)
|
||||
description = get_in(data, ["alt_text", "text"]) || data["name"] || data["description"]
|
||||
|
||||
{conn, status, response_body} =
|
||||
cond do
|
||||
!object ->
|
||||
{halt(conn), :not_found, ""}
|
||||
|
||||
!Object.authorize_mutation(object, user) ->
|
||||
{halt(conn), :forbidden, "You can only update your own uploads."}
|
||||
|
||||
!is_binary(description) ->
|
||||
{conn, :not_modified, ""}
|
||||
|
||||
true ->
|
||||
new_data = Map.put(object.data, "name", description)
|
||||
|
||||
{:ok, _} =
|
||||
object
|
||||
|> Object.change(%{data: new_data})
|
||||
|> Repo.update()
|
||||
|
||||
{conn, :no_content, ""}
|
||||
end
|
||||
|
||||
conn
|
||||
|> put_status(status)
|
||||
|> json(response_body)
|
||||
end
|
||||
|
||||
def upload(%{assigns: %{user: user}} = conn, %{"media" => media}) do
|
||||
response = TwitterAPI.upload(media, user)
|
||||
|
||||
conn
|
||||
|> put_resp_content_type("application/atom+xml")
|
||||
|> send_resp(200, response)
|
||||
end
|
||||
|
||||
def upload_json(conn, %{"media" => media}) do
|
||||
response = TwitterAPI.upload(media, "json")
|
||||
def upload_json(%{assigns: %{user: user}} = conn, %{"media" => media}) do
|
||||
response = TwitterAPI.upload(media, user, "json")
|
||||
|
||||
conn
|
||||
|> json_reply(200, response)
|
||||
|
|
@ -290,11 +325,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
|
|||
end
|
||||
|
||||
def update_avatar(%{assigns: %{user: user}} = conn, params) do
|
||||
upload_limit =
|
||||
Application.get_env(:pleroma, :instance)
|
||||
|> Keyword.fetch(:avatar_upload_limit)
|
||||
|
||||
{:ok, object} = ActivityPub.upload(params, upload_limit)
|
||||
{:ok, object} = ActivityPub.upload(params, type: :avatar)
|
||||
change = Changeset.change(user, %{avatar: object.data})
|
||||
{:ok, user} = User.update_and_set_cache(change)
|
||||
CommonAPI.update(user)
|
||||
|
|
@ -303,14 +334,11 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
|
|||
end
|
||||
|
||||
def update_banner(%{assigns: %{user: user}} = conn, params) do
|
||||
upload_limit =
|
||||
Application.get_env(:pleroma, :instance)
|
||||
|> Keyword.fetch(:banner_upload_limit)
|
||||
|
||||
with {:ok, object} <- ActivityPub.upload(%{"img" => params["banner"]}, upload_limit),
|
||||
new_info <- Map.put(user.info, "banner", object.data),
|
||||
change <- User.info_changeset(user, %{info: new_info}),
|
||||
{:ok, user} <- User.update_and_set_cache(change) do
|
||||
with {:ok, object} <- ActivityPub.upload(%{"img" => params["banner"]}, type: :banner),
|
||||
new_info <- %{"banner" => object.data},
|
||||
info_cng <- User.Info.profile_update(user.info, new_info),
|
||||
changeset <- Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_cng),
|
||||
{:ok, user} <- User.update_and_set_cache(changeset) do
|
||||
CommonAPI.update(user)
|
||||
%{"url" => [%{"href" => href} | _]} = object.data
|
||||
response = %{url: href} |> Jason.encode!()
|
||||
|
|
@ -321,14 +349,11 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
|
|||
end
|
||||
|
||||
def update_background(%{assigns: %{user: user}} = conn, params) do
|
||||
upload_limit =
|
||||
Application.get_env(:pleroma, :instance)
|
||||
|> Keyword.fetch(:background_upload_limit)
|
||||
|
||||
with {:ok, object} <- ActivityPub.upload(params, upload_limit),
|
||||
new_info <- Map.put(user.info, "background", object.data),
|
||||
change <- User.info_changeset(user, %{info: new_info}),
|
||||
{:ok, _user} <- User.update_and_set_cache(change) do
|
||||
with {:ok, object} <- ActivityPub.upload(params, type: :background),
|
||||
new_info <- %{"background" => object.data},
|
||||
info_cng <- User.Info.profile_update(user.info, new_info),
|
||||
changeset <- Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_cng),
|
||||
{:ok, _user} <- User.update_and_set_cache(changeset) do
|
||||
%{"url" => [%{"href" => href} | _]} = object.data
|
||||
response = %{url: href} |> Jason.encode!()
|
||||
|
||||
|
|
@ -350,32 +375,32 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
|
|||
end
|
||||
end
|
||||
|
||||
def update_most_recent_notification(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
||||
with id when is_number(id) <- String.to_integer(id),
|
||||
info <- user.info,
|
||||
mrn <- max(id, user.info["most_recent_notification"] || 0),
|
||||
updated_info <- Map.put(info, "most_recent_notification", mrn),
|
||||
changeset <- User.info_changeset(user, %{info: updated_info}),
|
||||
{:ok, _user} <- User.update_and_set_cache(changeset) do
|
||||
conn
|
||||
|> json_reply(200, Jason.encode!(mrn))
|
||||
else
|
||||
_e -> bad_request_reply(conn, "Can't update.")
|
||||
end
|
||||
end
|
||||
|
||||
def followers(conn, params) do
|
||||
with {:ok, user} <- TwitterAPI.get_user(conn.assigns[:user], params),
|
||||
def followers(%{assigns: %{user: for_user}} = conn, params) do
|
||||
with {:ok, user} <- TwitterAPI.get_user(for_user, params),
|
||||
{:ok, followers} <- User.get_followers(user) do
|
||||
followers =
|
||||
cond do
|
||||
for_user && user.id == for_user.id -> followers
|
||||
user.info.hide_network -> []
|
||||
true -> followers
|
||||
end
|
||||
|
||||
render(conn, UserView, "index.json", %{users: followers, for: conn.assigns[:user]})
|
||||
else
|
||||
_e -> bad_request_reply(conn, "Can't get followers")
|
||||
end
|
||||
end
|
||||
|
||||
def friends(conn, params) do
|
||||
def friends(%{assigns: %{user: for_user}} = conn, params) do
|
||||
with {:ok, user} <- TwitterAPI.get_user(conn.assigns[:user], params),
|
||||
{:ok, friends} <- User.get_friends(user) do
|
||||
friends =
|
||||
cond do
|
||||
for_user && user.id == for_user.id -> friends
|
||||
user.info.hide_network -> []
|
||||
true -> friends
|
||||
end
|
||||
|
||||
render(conn, UserView, "index.json", %{users: friends, for: conn.assigns[:user]})
|
||||
else
|
||||
_e -> bad_request_reply(conn, "Can't get friends")
|
||||
|
|
@ -451,67 +476,41 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
|
|||
json(conn, [])
|
||||
end
|
||||
|
||||
defp build_info_cng(user, params) do
|
||||
info_params =
|
||||
["no_rich_text", "locked", "hide_network"]
|
||||
|> Enum.reduce(%{}, fn key, res ->
|
||||
if value = params[key] do
|
||||
Map.put(res, key, value == "true")
|
||||
else
|
||||
res
|
||||
end
|
||||
end)
|
||||
|
||||
info_params =
|
||||
if value = params["default_scope"] do
|
||||
Map.put(info_params, "default_scope", value)
|
||||
else
|
||||
info_params
|
||||
end
|
||||
|
||||
User.Info.profile_update(user.info, info_params)
|
||||
end
|
||||
|
||||
defp parse_profile_bio(user, params) do
|
||||
if bio = params["description"] do
|
||||
Map.put(params, "bio", User.parse_bio(bio, user))
|
||||
else
|
||||
params
|
||||
end
|
||||
end
|
||||
|
||||
def update_profile(%{assigns: %{user: user}} = conn, params) do
|
||||
params =
|
||||
if bio = params["description"] do
|
||||
mentions = Formatter.parse_mentions(bio)
|
||||
tags = Formatter.parse_tags(bio)
|
||||
|
||||
emoji =
|
||||
(user.info["source_data"]["tag"] || [])
|
||||
|> Enum.filter(fn %{"type" => t} -> t == "Emoji" end)
|
||||
|> Enum.map(fn %{"icon" => %{"url" => url}, "name" => name} ->
|
||||
{String.trim(name, ":"), url}
|
||||
end)
|
||||
|
||||
bio_html = CommonUtils.format_input(bio, mentions, tags, "text/plain")
|
||||
Map.put(params, "bio", bio_html |> Formatter.emojify(emoji))
|
||||
else
|
||||
params
|
||||
end
|
||||
|
||||
user =
|
||||
if locked = params["locked"] do
|
||||
with locked <- locked == "true",
|
||||
new_info <- Map.put(user.info, "locked", locked),
|
||||
change <- User.info_changeset(user, %{info: new_info}),
|
||||
{:ok, user} <- User.update_and_set_cache(change) do
|
||||
user
|
||||
else
|
||||
_e -> user
|
||||
end
|
||||
else
|
||||
user
|
||||
end
|
||||
|
||||
user =
|
||||
if no_rich_text = params["no_rich_text"] do
|
||||
with no_rich_text <- no_rich_text == "true",
|
||||
new_info <- Map.put(user.info, "no_rich_text", no_rich_text),
|
||||
change <- User.info_changeset(user, %{info: new_info}),
|
||||
{:ok, user} <- User.update_and_set_cache(change) do
|
||||
user
|
||||
else
|
||||
_e -> user
|
||||
end
|
||||
else
|
||||
user
|
||||
end
|
||||
|
||||
user =
|
||||
if default_scope = params["default_scope"] do
|
||||
with new_info <- Map.put(user.info, "default_scope", default_scope),
|
||||
change <- User.info_changeset(user, %{info: new_info}),
|
||||
{:ok, user} <- User.update_and_set_cache(change) do
|
||||
user
|
||||
else
|
||||
_e -> user
|
||||
end
|
||||
else
|
||||
user
|
||||
end
|
||||
params = parse_profile_bio(user, params)
|
||||
info_cng = build_info_cng(user, params)
|
||||
|
||||
with changeset <- User.update_changeset(user, params),
|
||||
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})
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ defmodule Pleroma.Web.TwitterAPI.UserView do
|
|||
user_info = User.get_cached_user_info(user)
|
||||
|
||||
emoji =
|
||||
(user.info["source_data"]["tag"] || [])
|
||||
(user.info.source_data["tag"] || [])
|
||||
|> Enum.filter(fn %{"type" => t} -> t == "Emoji" end)
|
||||
|> Enum.map(fn %{"icon" => %{"url" => url}, "name" => name} ->
|
||||
{String.trim(name, ":"), url}
|
||||
|
|
@ -40,7 +40,7 @@ defmodule Pleroma.Web.TwitterAPI.UserView do
|
|||
# ``fields`` is an array of mastodon profile field, containing ``{"name": "…", "value": "…"}``.
|
||||
# For example: [{"name": "Pronoun", "value": "she/her"}, …]
|
||||
fields =
|
||||
(user.info["source_data"]["attachment"] || [])
|
||||
(user.info.source_data["attachment"] || [])
|
||||
|> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end)
|
||||
|> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end)
|
||||
|
||||
|
|
@ -66,17 +66,17 @@ defmodule Pleroma.Web.TwitterAPI.UserView do
|
|||
"profile_image_url_profile_size" => image,
|
||||
"profile_image_url_original" => image,
|
||||
"rights" => %{
|
||||
"delete_others_notice" => !!user.info["is_moderator"]
|
||||
"delete_others_notice" => !!user.info.is_moderator
|
||||
},
|
||||
"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(),
|
||||
"background_image" => image_url(user.info.background) |> MediaProxy.url(),
|
||||
"is_local" => user.local,
|
||||
"locked" => !!user.info["locked"],
|
||||
"default_scope" => user.info["default_scope"] || "public",
|
||||
"no_rich_text" => user.info["no_rich_text"] || false,
|
||||
"locked" => user.info.locked,
|
||||
"default_scope" => user.info.default_scope,
|
||||
"no_rich_text" => user.info.no_rich_text,
|
||||
"fields" => fields
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ defmodule Pleroma.Web.WebFinger do
|
|||
|
||||
def represent_user(user, "JSON") do
|
||||
{:ok, user} = ensure_keys_present(user)
|
||||
{:ok, _private, public} = Salmon.keys_from_pem(user.info["keys"])
|
||||
{:ok, _private, public} = Salmon.keys_from_pem(user.info.keys)
|
||||
magic_key = Salmon.encode_key(public)
|
||||
|
||||
%{
|
||||
|
|
@ -83,7 +83,7 @@ defmodule Pleroma.Web.WebFinger do
|
|||
|
||||
def represent_user(user, "XML") do
|
||||
{:ok, user} = ensure_keys_present(user)
|
||||
{:ok, _private, public} = Salmon.keys_from_pem(user.info["keys"])
|
||||
{:ok, _private, public} = Salmon.keys_from_pem(user.info.keys)
|
||||
magic_key = Salmon.encode_key(public)
|
||||
|
||||
{
|
||||
|
|
@ -113,16 +113,22 @@ defmodule Pleroma.Web.WebFinger do
|
|||
|
||||
# This seems a better fit in Salmon
|
||||
def ensure_keys_present(user) do
|
||||
info = user.info || %{}
|
||||
info = user.info
|
||||
|
||||
if info["keys"] do
|
||||
if info.keys do
|
||||
{:ok, user}
|
||||
else
|
||||
{:ok, pem} = Salmon.generate_rsa_pem()
|
||||
info = Map.put(info, "keys", pem)
|
||||
|
||||
Ecto.Changeset.change(user, info: info)
|
||||
|> User.update_and_set_cache()
|
||||
info_cng =
|
||||
info
|
||||
|> Pleroma.User.Info.set_keys(pem)
|
||||
|
||||
cng =
|
||||
Ecto.Changeset.change(user)
|
||||
|> Ecto.Changeset.put_embed(:info, info_cng)
|
||||
|
||||
User.update_and_set_cache(cng)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -214,7 +220,7 @@ defmodule Pleroma.Web.WebFinger do
|
|||
end
|
||||
|
||||
def find_lrdd_template(domain) do
|
||||
with {:ok, %{status_code: status_code, body: body}} when status_code in 200..299 <-
|
||||
with {:ok, %{status: status, body: body}} when status in 200..299 <-
|
||||
@httpoison.get("http://#{domain}/.well-known/host-meta", [], follow_redirect: true) do
|
||||
get_template_from_xml(body)
|
||||
else
|
||||
|
|
@ -253,7 +259,7 @@ defmodule Pleroma.Web.WebFinger do
|
|||
[Accept: "application/xrd+xml,application/jrd+json"],
|
||||
follow_redirect: true
|
||||
),
|
||||
{:ok, %{status_code: status_code, body: body}} when status_code in 200..299 <- response do
|
||||
{:ok, %{status: status, body: body}} when status in 200..299 <- response do
|
||||
doc = XML.parse_document(body)
|
||||
|
||||
if doc != :error do
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ defmodule Pleroma.Web.Websub do
|
|||
end
|
||||
|
||||
def subscribe(subscriber, subscribed, requester \\ &request_subscription/1) do
|
||||
topic = subscribed.info["topic"]
|
||||
topic = subscribed.info.topic
|
||||
# FIXME: Race condition, use transactions
|
||||
{:ok, subscription} =
|
||||
with subscription when not is_nil(subscription) <-
|
||||
|
|
@ -158,7 +158,7 @@ defmodule Pleroma.Web.Websub do
|
|||
_e ->
|
||||
subscription = %WebsubClientSubscription{
|
||||
topic: topic,
|
||||
hub: subscribed.info["hub"],
|
||||
hub: subscribed.info.hub,
|
||||
subscribers: [subscriber.ap_id],
|
||||
state: "requested",
|
||||
secret: :crypto.strong_rand_bytes(8) |> Base.url_encode64(),
|
||||
|
|
@ -173,7 +173,7 @@ defmodule Pleroma.Web.Websub do
|
|||
|
||||
def gather_feed_data(topic, getter \\ &@httpoison.get/1) do
|
||||
with {:ok, response} <- getter.(topic),
|
||||
status_code when status_code in 200..299 <- response.status_code,
|
||||
status when status in 200..299 <- response.status,
|
||||
body <- response.body,
|
||||
doc <- XML.parse_document(body),
|
||||
uri when not is_nil(uri) <- XML.string_from_xpath("/feed/author[1]/uri", doc),
|
||||
|
|
@ -221,7 +221,7 @@ defmodule Pleroma.Web.Websub do
|
|||
|
||||
task = Task.async(websub_checker)
|
||||
|
||||
with {:ok, %{status_code: 202}} <-
|
||||
with {:ok, %{status: 202}} <-
|
||||
poster.(websub.hub, {:form, data}, "Content-type": "application/x-www-form-urlencoded"),
|
||||
{:ok, websub} <- Task.yield(task, timeout) do
|
||||
{:ok, websub}
|
||||
|
|
@ -257,7 +257,7 @@ defmodule Pleroma.Web.Websub do
|
|||
signature = sign(secret || "", xml)
|
||||
Logger.info(fn -> "Pushing #{topic} to #{callback}" end)
|
||||
|
||||
with {:ok, %{status_code: code}} <-
|
||||
with {:ok, %{status: code}} <-
|
||||
@httpoison.post(
|
||||
callback,
|
||||
xml,
|
||||
|
|
@ -265,9 +265,11 @@ defmodule Pleroma.Web.Websub do
|
|||
{"Content-Type", "application/atom+xml"},
|
||||
{"X-Hub-Signature", "sha1=#{signature}"}
|
||||
],
|
||||
timeout: 10000,
|
||||
recv_timeout: 20000,
|
||||
hackney: [pool: :default]
|
||||
adapter: [
|
||||
timeout: 10000,
|
||||
recv_timeout: 20000,
|
||||
pool: :default
|
||||
]
|
||||
) do
|
||||
Logger.info(fn -> "Pushed to #{callback}, code #{code}" end)
|
||||
{:ok, code}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue