Merge develop

This commit is contained in:
Rin Toshaka 2018-12-06 18:11:22 +01:00
commit 88f92693f2
40 changed files with 918 additions and 140 deletions

View file

@ -29,6 +29,12 @@ config :pleroma, Pleroma.Repo,
hostname: "<%= dbhost %>",
pool_size: 10
# Configure web push notifications
config :web_push_encryption, :vapid_details,
subject: "mailto:<%= email %>",
public_key: "<%= web_push_public_key %>",
private_key: "<%= web_push_private_key %>"
# Enable Strict-Transport-Security once SSL is working:
# config :pleroma, :http_security,
# sts: true
@ -54,9 +60,9 @@ config :pleroma, Pleroma.Repo,
# Configure Openstack Swift support if desired.
#
# Many openstack deployments are different, so config is left very open with
# no assumptions made on which provider you're using. This should allow very
#
# Many openstack deployments are different, so config is left very open with
# no assumptions made on which provider you're using. This should allow very
# wide support without needing separate handlers for OVH, Rackspace, etc.
#
# config :pleroma, Pleroma.Uploaders.Swift,

View file

@ -66,7 +66,8 @@ defmodule Pleroma.Application do
),
worker(Pleroma.Web.Federator.RetryQueue, []),
worker(Pleroma.Web.Federator, []),
worker(Pleroma.Stats, [])
worker(Pleroma.Stats, []),
worker(Pleroma.Web.Push, [])
] ++
streamer_child() ++
chat_child() ++

View file

@ -114,7 +114,7 @@ defmodule Pleroma.Formatter do
subs =
subs ++
Enum.map(mentions, fn {match, %User{ap_id: ap_id, info: info}, uuid} ->
Enum.map(mentions, fn {match, %User{id: id, ap_id: ap_id, info: info}, uuid} ->
ap_id =
if is_binary(info.source_data["url"]) do
info.source_data["url"]
@ -125,7 +125,7 @@ defmodule Pleroma.Formatter do
short_match = String.split(match, "@") |> tl() |> hd()
{uuid,
"<span><a class='mention' href='#{ap_id}'>@<span>#{short_match}</span></a></span>"}
"<span><a data-user='#{id}' class='mention' href='#{ap_id}'>@<span>#{short_match}</span></a></span>"}
end)
{subs, uuid_text}
@ -147,7 +147,11 @@ defmodule Pleroma.Formatter do
subs =
subs ++
Enum.map(tags, fn {tag_text, tag, uuid} ->
url = "<a href='#{Pleroma.Web.base_url()}/tag/#{tag}' rel='tag'>#{tag_text}</a>"
url =
"<a data-tag='#{tag}' href='#{Pleroma.Web.base_url()}/tag/#{tag}' rel='tag'>#{
tag_text
}</a>"
{uuid, url}
end)

View file

@ -45,7 +45,7 @@ defmodule Pleroma.HTML.Scrubber.TwitterText do
Meta.strip_comments()
# links
Meta.allow_tag_with_uri_attributes("a", ["href"], @valid_schemes)
Meta.allow_tag_with_uri_attributes("a", ["href", "data-user", "data-tag"], @valid_schemes)
Meta.allow_tag_with_these_attributes("a", ["name", "title"])
# paragraphs and linebreaks
@ -86,7 +86,7 @@ defmodule Pleroma.HTML.Scrubber.Default do
Meta.remove_cdata_sections_before_scrub()
Meta.strip_comments()
Meta.allow_tag_with_uri_attributes("a", ["href"], @valid_schemes)
Meta.allow_tag_with_uri_attributes("a", ["href", "data-user", "data-tag"], @valid_schemes)
Meta.allow_tag_with_these_attributes("a", ["name", "title"])
Meta.allow_tag_with_these_attributes("abbr", ["title"])

View file

@ -3,7 +3,12 @@ defmodule Pleroma.HTTP.Connection do
Connection for http-requests.
"""
@hackney_options [pool: :default]
@hackney_options [
pool: :default,
timeout: 10000,
recv_timeout: 20000,
follow_redirect: true
]
@adapter Application.get_env(:tesla, :adapter)
@doc """

View file

@ -110,6 +110,7 @@ defmodule Pleroma.Notification do
notification = %Notification{user_id: user.id, activity: activity}
{:ok, notification} = Repo.insert(notification)
Pleroma.Web.Streamer.stream("user", notification)
Pleroma.Web.Push.send(notification)
notification
end
end

View file

@ -1,6 +1,6 @@
defmodule Pleroma.Object do
use Ecto.Schema
alias Pleroma.{Repo, Object, Activity}
alias Pleroma.{Repo, Object, User, Activity}
import Ecto.{Query, Changeset}
schema "objects" do
@ -31,6 +31,13 @@ defmodule Pleroma.Object do
def normalize(ap_id) when is_binary(ap_id), do: Object.get_by_ap_id(ap_id)
def normalize(_), do: nil
# Owned objects can only be mutated by their owner
def authorize_mutation(%Object{data: %{"actor" => actor}}, %User{ap_id: ap_id}),
do: actor == ap_id
# Legacy objects can be mutated by anybody
def authorize_mutation(%Object{}, %User{}), do: true
if Mix.env() == :test do
def get_cached_by_ap_id(ap_id) do
get_by_ap_id(ap_id)

View file

@ -1,30 +1,70 @@
defmodule Pleroma.Plugs.OAuthPlug do
import Plug.Conn
alias Pleroma.User
alias Pleroma.Repo
alias Pleroma.Web.OAuth.Token
import Ecto.Query
def init(options) do
options
end
alias Pleroma.{
User,
Repo,
Web.OAuth.Token
}
@realm_reg Regex.compile!("Bearer\:?\s+(.*)$", "i")
def init(options), do: options
def call(%{assigns: %{user: %User{}}} = conn, _), do: conn
def call(conn, _) do
token =
case get_req_header(conn, "authorization") do
["Bearer " <> header] -> header
_ -> get_session(conn, :oauth_token)
end
with token when not is_nil(token) <- token,
%Token{user_id: user_id} <- Repo.get_by(Token, token: token),
%User{} = user <- Repo.get(User, user_id),
false <- !!user.info.deactivated do
with {:ok, token} <- fetch_token(conn),
{:ok, user} <- fetch_user(token) do
conn
|> assign(:token, token)
|> assign(:user, user)
else
_ -> conn
end
end
# Gets user by token
#
@spec fetch_user(String.t()) :: {:ok, User.t()} | nil
defp fetch_user(token) do
query = from(q in Token, where: q.token == ^token, preload: [:user])
with %Token{user: %{info: %{deactivated: false} = _} = user} <- Repo.one(query) do
{:ok, user}
end
end
# Gets token from session by :oauth_token key
#
@spec fetch_token_from_session(Plug.Conn.t()) :: :no_token_found | {:ok, String.t()}
defp fetch_token_from_session(conn) do
case get_session(conn, :oauth_token) do
nil -> :no_token_found
token -> {:ok, token}
end
end
# Gets token from headers
#
@spec fetch_token(Plug.Conn.t()) :: :no_token_found | {:ok, String.t()}
defp fetch_token(%Plug.Conn{} = conn) do
headers = get_req_header(conn, "authorization")
with :no_token_found <- fetch_token(headers),
do: fetch_token_from_session(conn)
end
@spec fetch_token(Keyword.t()) :: :no_token_found | {:ok, String.t()}
defp fetch_token([]), do: :no_token_found
defp fetch_token([token | tail]) do
trimmed_token = String.trim(token)
case Regex.run(@realm_reg, trimmed_token) do
[_, match] -> {:ok, String.trim(match)}
_ -> fetch_token(tail)
end
end
end

View file

@ -56,7 +56,7 @@ defmodule Pleroma.ReverseProxy do
@hackney Application.get_env(:pleroma, :hackney, :hackney)
@httpoison Application.get_env(:pleroma, :httpoison, HTTPoison)
@default_hackney_options [{:follow_redirect, true}]
@default_hackney_options []
@inline_content_types [
"image/gif",

View file

@ -62,10 +62,6 @@ defmodule Pleroma.User do
|> validate_required([:following])
end
def info_changeset(struct, params \\ %{}) do
raise "NOT VALID ANYMORE"
end
def user_info(%User{} = user) do
oneself = if user.local, do: 1, else: 0

View file

@ -24,6 +24,7 @@ defmodule Pleroma.User.Info do
field(:topic, :string, default: nil)
field(:hub, :string, default: nil)
field(:salmon, :string, default: nil)
field(:hide_network, :boolean, default: false)
# Found in the wild
# ap_id -> Where is this used?
@ -135,6 +136,7 @@ defmodule Pleroma.User.Info do
:no_rich_text,
:default_scope,
:banner,
:hide_network,
:background
])
end
@ -147,6 +149,11 @@ defmodule Pleroma.User.Info do
])
end
def mastodon_settings_update(info, params) do
info
|> cast(params, [:settings])
end
def set_source_data(info, source_data) do
params = %{source_data: source_data}

View file

@ -574,7 +574,14 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
def upload(file, opts \\ []) do
with {:ok, data} <- Upload.store(file, opts) do
Repo.insert(%Object{data: data})
obj_data =
if opts[:actor] do
Map.put(data, "actor", opts[:actor])
else
data
end
Repo.insert(%Object{data: obj_data})
end
end
@ -765,10 +772,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
{:ok, %{body: body, status: code}} when code in 200..299 <-
@httpoison.get(
id,
[Accept: "application/activity+json"],
follow_redirect: true,
timeout: 10000,
recv_timeout: 20000
[{:Accept, "application/activity+json"}]
),
{:ok, data} <- Jason.decode(body),
:ok <- Transmogrifier.contain_origin_from_id(id, data) do

View file

@ -0,0 +1,40 @@
defmodule Pleroma.Web.ActivityPub.MRF.EnsureRePrepended do
alias Pleroma.Object
@behaviour Pleroma.Web.ActivityPub.MRF
@reply_prefix Regex.compile!("^re:[[:space:]]*", [:caseless])
def filter_by_summary(
%{"summary" => parent_summary} = parent,
%{"summary" => child_summary} = child
)
when not is_nil(child_summary) and byte_size(child_summary) > 0 and
not is_nil(parent_summary) and byte_size(parent_summary) > 0 do
if (child_summary == parent_summary and not Regex.match?(@reply_prefix, child_summary)) or
(Regex.match?(@reply_prefix, parent_summary) &&
Regex.replace(@reply_prefix, parent_summary, "") == child_summary) do
Map.put(child, "summary", "re: " <> child_summary)
else
child
end
end
def filter_by_summary(parent, child), do: child
def filter(%{"type" => activity_type} = object) when activity_type == "Create" do
child = object["object"]
in_reply_to = Object.normalize(child["inReplyTo"])
child =
if(in_reply_to,
do: filter_by_summary(in_reply_to.data, child),
else: child
)
object = Map.put(object, "object", child)
{:ok, object}
end
def filter(object), do: {:ok, object}
end

View file

@ -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

View file

@ -2,13 +2,22 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
use Pleroma.Web, :controller
alias Pleroma.{Repo, Object, Activity, User, Notification, Stats}
alias Pleroma.Web
alias Pleroma.Web.MastodonAPI.{StatusView, AccountView, MastodonView, ListView, FilterView}
alias Pleroma.Web.MastodonAPI.{
StatusView,
AccountView,
MastodonView,
ListView,
FilterView,
PushSubscriptionView
}
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.OAuth.{Authorization, Token, App}
alias Pleroma.Web.MediaProxy
alias Comeonin.Pbkdf2
import Ecto.Query
require Logger
@ -433,33 +442,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, description: Map.get(data, "description")) do
change = Object.change(object, %{data: object.data})
{:ok, object} = Repo.update(change)
objdata =
object.data
|> 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
@ -502,17 +509,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
@ -959,9 +979,11 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def put_settings(%{assigns: %{user: user}} = conn, %{"data" => settings} = _params) do
with new_info <- Map.put(user.info, "settings", settings),
change <- User.info_changeset(user, %{info: new_info}),
{:ok, _user} <- User.update_and_set_cache(change) do
info_cng = User.Info.mastodon_settings_update(user.info, settings)
with changeset <- User.update_changeset(user),
changeset <- Ecto.Changeset.put_embed(changeset, :info, info_cng),
{:ok, user} <- User.update_and_set_cache(changeset) do
conn
|> json(%{})
else
@ -1149,6 +1171,33 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
json(conn, %{})
end
def create_push_subscription(%{assigns: %{user: user, token: token}} = conn, params) do
Pleroma.Web.Push.Subscription.delete_if_exists(user, token)
{:ok, subscription} = Pleroma.Web.Push.Subscription.create(user, token, params)
view = PushSubscriptionView.render("push_subscription.json", subscription: subscription)
json(conn, view)
end
def get_push_subscription(%{assigns: %{user: user, token: token}} = conn, _params) do
subscription = Pleroma.Web.Push.Subscription.get(user, token)
view = PushSubscriptionView.render("push_subscription.json", subscription: subscription)
json(conn, view)
end
def update_push_subscription(
%{assigns: %{user: user, token: token}} = conn,
params
) do
{:ok, subscription} = Pleroma.Web.Push.Subscription.update(user, token, params)
view = PushSubscriptionView.render("push_subscription.json", subscription: subscription)
json(conn, view)
end
def delete_push_subscription(%{assigns: %{user: user, token: token}} = conn, _params) do
{:ok, _response} = Pleroma.Web.Push.Subscription.delete(user, token)
json(conn, %{})
end
def errors(conn, _) do
conn
|> put_status(500)
@ -1169,7 +1218,14 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
url = String.replace(api, "{{host}}", host) |> String.replace("{{user}}", user)
with {:ok, %{status: 200, body: body}} <-
@httpoison.get(url, [], timeout: timeout, recv_timeout: timeout),
@httpoison.get(
url,
[],
adapter: [
timeout: timeout,
recv_timeout: timeout
]
),
{:ok, data} <- Jason.decode(body) do
data2 =
Enum.slice(data, 0, limit)

View file

@ -0,0 +1,12 @@
defmodule Pleroma.Web.MastodonAPI.PushSubscriptionView do
use Pleroma.Web, :view
alias Pleroma.Web.MastodonAPI.PushSubscriptionView
def render("push_subscription.json", %{subscription: subscription}) do
%{
id: to_string(subscription.id),
endpoint: subscription.endpoint,
alerts: Map.get(subscription.data, "alerts")
}
end
end

View file

@ -349,12 +349,7 @@ defmodule Pleroma.Web.OStatus do
{:ok, %{body: body, status: code}} when code in 200..299 <-
@httpoison.get(
url,
[Accept: "application/atom+xml"],
follow_redirect: true,
adapter: [
timeout: 10000,
recv_timeout: 20000
]
[{:Accept, "application/atom+xml"}]
) do
Logger.debug("Got document from #{url}, handling...")
handle_incoming(body)
@ -369,8 +364,7 @@ defmodule Pleroma.Web.OStatus do
Logger.debug("Trying to fetch #{url}")
with true <- String.starts_with?(url, "http"),
{:ok, %{body: body}} <-
@httpoison.get(url, [], follow_redirect: true, timeout: 10000, recv_timeout: 20000),
{:ok, %{body: body}} <- @httpoison.get(url, []),
{:ok, atom_url} <- get_atom_url(body) do
fetch_activity_from_atom_url(atom_url)
else

View file

@ -0,0 +1,116 @@
defmodule Pleroma.Web.Push do
use GenServer
alias Pleroma.{Repo, User}
alias Pleroma.Web.Push.Subscription
require Logger
import Ecto.Query
@types ["Create", "Follow", "Announce", "Like"]
@gcm_api_key nil
def start_link() do
GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
end
def init(:ok) do
case Application.get_env(:web_push_encryption, :vapid_details) do
nil ->
Logger.warn(
"VAPID key pair is not found. Please, add VAPID configuration to config. Run `mix web_push.gen.keypair` mix task to create a key pair"
)
:ignore
_ ->
{:ok, %{}}
end
end
def send(notification) do
if Application.get_env(:web_push_encryption, :vapid_details) do
GenServer.cast(Pleroma.Web.Push, {:send, notification})
end
end
def handle_cast(
{:send, %{activity: %{data: %{"type" => type}}, user_id: user_id} = notification},
state
)
when type in @types do
actor = User.get_cached_by_ap_id(notification.activity.data["actor"])
body = notification |> format(actor) |> Jason.encode!()
Subscription
|> where(user_id: ^user_id)
|> Repo.all()
|> Enum.each(fn record ->
subscription = %{
keys: %{
p256dh: record.key_p256dh,
auth: record.key_auth
},
endpoint: record.endpoint
}
case WebPushEncryption.send_web_push(body, subscription, @gcm_api_key) do
{:ok, %{status_code: code}} when 400 <= code and code < 500 ->
Logger.debug("Removing subscription record")
Repo.delete!(record)
:ok
{:ok, %{status_code: code}} when 200 <= code and code < 300 ->
:ok
{:ok, %{status_code: code}} ->
Logger.error("Web Push Nonification failed with code: #{code}")
:error
_ ->
Logger.error("Web Push Nonification failed with unknown error")
:error
end
end)
{:noreply, state}
end
def handle_cast({:send, _}, state) do
Logger.warn("Unknown notification type")
{:noreply, state}
end
def format(%{activity: %{data: %{"type" => "Create"}}}, actor) do
%{
title: "New Mention",
body: "@#{actor.nickname} has mentiond you",
icon: User.avatar_url(actor)
}
end
def format(%{activity: %{data: %{"type" => "Follow"}}}, actor) do
%{
title: "New Follower",
body: "@#{actor.nickname} has followed you",
icon: User.avatar_url(actor)
}
end
def format(%{activity: %{data: %{"type" => "Announce"}}}, actor) do
%{
title: "New Announce",
body: "@#{actor.nickname} has announced your post",
icon: User.avatar_url(actor)
}
end
def format(%{activity: %{data: %{"type" => "Like"}}}, actor) do
%{
title: "New Like",
body: "@#{actor.nickname} has liked your post",
icon: User.avatar_url(actor)
}
end
end

View file

@ -0,0 +1,66 @@
defmodule Pleroma.Web.Push.Subscription do
use Ecto.Schema
import Ecto.Changeset
alias Pleroma.{Repo, User}
alias Pleroma.Web.OAuth.Token
alias Pleroma.Web.Push.Subscription
schema "push_subscriptions" do
belongs_to(:user, User)
belongs_to(:token, Token)
field(:endpoint, :string)
field(:key_p256dh, :string)
field(:key_auth, :string)
field(:data, :map, default: %{})
timestamps()
end
@supported_alert_types ~w[follow favourite mention reblog]
defp alerts(%{"data" => %{"alerts" => alerts}}) do
alerts = Map.take(alerts, @supported_alert_types)
%{"alerts" => alerts}
end
def create(
%User{} = user,
%Token{} = token,
%{
"subscription" => %{
"endpoint" => endpoint,
"keys" => %{"auth" => key_auth, "p256dh" => key_p256dh}
}
} = params
) do
Repo.insert(%Subscription{
user_id: user.id,
token_id: token.id,
endpoint: endpoint,
key_auth: key_auth,
key_p256dh: key_p256dh,
data: alerts(params)
})
end
def get(%User{id: user_id}, %Token{id: token_id}) do
Repo.get_by(Subscription, user_id: user_id, token_id: token_id)
end
def update(user, token, params) do
get(user, token)
|> change(data: alerts(params))
|> Repo.update()
end
def delete(user, token) do
Repo.delete(get(user, token))
end
def delete_if_exists(user, token) do
case get(user, token) do
nil -> {:ok, nil}
sub -> Repo.delete(sub)
end
end
end

View file

@ -198,6 +198,11 @@ defmodule Pleroma.Web.Router do
put("/filters/:id", MastodonAPIController, :update_filter)
delete("/filters/:id", MastodonAPIController, :delete_filter)
post("/push/subscription", MastodonAPIController, :create_push_subscription)
get("/push/subscription", MastodonAPIController, :get_push_subscription)
put("/push/subscription", MastodonAPIController, :update_push_subscription)
delete("/push/subscription", MastodonAPIController, :delete_push_subscription)
get("/suggestions", MastodonAPIController, :suggestions)
get("/endorsements", MastodonAPIController, :empty_array)
@ -324,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)

View file

@ -162,12 +162,7 @@ defmodule Pleroma.Web.Salmon do
poster.(
salmon,
feed,
[{"Content-Type", "application/magic-envelope+xml"}],
adapter: [
timeout: 10000,
recv_timeout: 20000,
pool: :default
]
[{"Content-Type", "application/magic-envelope+xml"}]
) do
Logger.debug(fn -> "Pushed to #{salmon}, code #{code}" end)
else

View file

@ -157,13 +157,17 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
|> send_resp(200, response)
_ ->
vapid_public_key =
Keyword.get(Application.get_env(:web_push_encryption, :vapid_details), :public_key)
data = %{
name: Keyword.get(instance, :name),
description: Keyword.get(instance, :description),
server: Web.base_url(),
textlimit: to_string(Keyword.get(instance, :limit)),
closed: if(Keyword.get(instance, :registrations_open), do: "0", else: "1"),
private: if(Keyword.get(instance, :public, true), do: "0", else: "1")
private: if(Keyword.get(instance, :public, true), do: "0", else: "1"),
vapidPublicKey: vapid_public_key
}
pleroma_fe = %{

View file

@ -93,8 +93,8 @@ 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"]

View file

@ -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)
@ -340,18 +375,32 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
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")
@ -429,7 +478,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
defp build_info_cng(user, params) do
info_params =
["no_rich_text", "locked"]
["no_rich_text", "locked", "hide_network"]
|> Enum.reduce(%{}, fn key, res ->
if value = params[key] do
Map.put(res, key, value == "true")

View file

@ -221,7 +221,7 @@ defmodule Pleroma.Web.WebFinger do
def find_lrdd_template(domain) do
with {:ok, %{status: status, body: body}} when status in 200..299 <-
@httpoison.get("http://#{domain}/.well-known/host-meta", [], follow_redirect: true) do
@httpoison.get("http://#{domain}/.well-known/host-meta", []) do
get_template_from_xml(body)
else
_ ->

View file

@ -264,11 +264,6 @@ defmodule Pleroma.Web.Websub do
[
{"Content-Type", "application/atom+xml"},
{"X-Hub-Signature", "sha1=#{signature}"}
],
adapter: [
timeout: 10000,
recv_timeout: 20000,
pool: :default
]
) do
Logger.info(fn -> "Pushed to #{callback}, code #{code}" end)