Merge branch 'release/2.0.4' into 'stable'

Release/2.0.4

See merge request pleroma/pleroma!2503
This commit is contained in:
rinpatch 2020-05-10 17:13:03 +00:00
commit a6283bbae1
10 changed files with 125 additions and 34 deletions

View File

@ -3,6 +3,31 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [2.0.4] - 2020-05-10
### Security
- AP C2S: Fix a potential DoS by creating nonsensical objects that break timelines
### Fixed
- Peertube user lookups not working
- `InsertSkeletonsForDeletedUsers` migration failing on some instances
- Healthcheck reporting the number of memory currently used, rather than allocated in total
- LDAP not being usable in OTP releases
- Default apache configuration having tls chain issues
### Upgrade notes
#### Apache only
1. Remove the following line from your config:
```
SSLCertificateFile /etc/letsencrypt/live/${servername}/cert.pem
```
#### Everyone
1. Restart Pleroma
## [2.0.3] - 2020-05-02 ## [2.0.3] - 2020-05-02
### Security ### Security

View File

@ -2260,6 +2260,7 @@
children: [ children: [
%{ %{
key: :active, key: :active,
label: "Enabled",
type: :boolean, type: :boolean,
description: "Globally enable or disable digest emails" description: "Globally enable or disable digest emails"
}, },

View File

@ -32,9 +32,8 @@ CustomLog ${APACHE_LOG_DIR}/access.log combined
<VirtualHost *:443> <VirtualHost *:443>
SSLEngine on SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/${servername}/cert.pem SSLCertificateFile /etc/letsencrypt/live/${servername}/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/${servername}/privkey.pem SSLCertificateKeyFile /etc/letsencrypt/live/${servername}/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/${servername}/fullchain.pem
# Mozilla modern configuration, tweak to your needs # Mozilla modern configuration, tweak to your needs
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1 SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1

View File

@ -29,7 +29,7 @@ defmodule Pleroma.Healthcheck do
@spec system_info() :: t() @spec system_info() :: t()
def system_info do def system_info do
%Healthcheck{ %Healthcheck{
memory_used: Float.round(:erlang.memory(:total) / 1024 / 1024, 2) memory_used: Float.round(:recon_alloc.memory(:allocated) / 1024 / 1024, 2)
} }
|> assign_db_info() |> assign_db_info()
|> assign_job_queue_stats() |> assign_job_queue_stats()

View File

@ -370,7 +370,10 @@ def read_inbox(%{assigns: %{user: %{nickname: as_nickname}}} = conn, %{
|> json(err) |> json(err)
end end
def handle_user_activity(user, %{"type" => "Create"} = params) do defp handle_user_activity(
%User{} = user,
%{"type" => "Create", "object" => %{"type" => "Note"}} = params
) do
object = object =
params["object"] params["object"]
|> Map.merge(Map.take(params, ["to", "cc"])) |> Map.merge(Map.take(params, ["to", "cc"]))
@ -386,7 +389,7 @@ def handle_user_activity(user, %{"type" => "Create"} = params) do
}) })
end end
def handle_user_activity(user, %{"type" => "Delete"} = params) do defp handle_user_activity(user, %{"type" => "Delete"} = params) do
with %Object{} = object <- Object.normalize(params["object"]), with %Object{} = object <- Object.normalize(params["object"]),
true <- user.is_moderator || user.ap_id == object.data["actor"], true <- user.is_moderator || user.ap_id == object.data["actor"],
{:ok, delete} <- ActivityPub.delete(object) do {:ok, delete} <- ActivityPub.delete(object) do
@ -396,7 +399,7 @@ def handle_user_activity(user, %{"type" => "Delete"} = params) do
end end
end end
def handle_user_activity(user, %{"type" => "Like"} = params) do defp handle_user_activity(user, %{"type" => "Like"} = params) do
with %Object{} = object <- Object.normalize(params["object"]), with %Object{} = object <- Object.normalize(params["object"]),
{:ok, activity, _object} <- ActivityPub.like(user, object) do {:ok, activity, _object} <- ActivityPub.like(user, object) do
{:ok, activity} {:ok, activity}
@ -405,7 +408,7 @@ def handle_user_activity(user, %{"type" => "Like"} = params) do
end end
end end
def handle_user_activity(_, _) do defp handle_user_activity(_, _) do
{:error, dgettext("errors", "Unhandled activity type")} {:error, dgettext("errors", "Unhandled activity type")}
end end

View File

@ -193,13 +193,15 @@ def finger(account) do
URI.parse(account).host URI.parse(account).host
end end
encoded_account = URI.encode("acct:#{account}")
address = address =
case find_lrdd_template(domain) do case find_lrdd_template(domain) do
{:ok, template} -> {:ok, template} ->
String.replace(template, "{uri}", URI.encode(account)) String.replace(template, "{uri}", encoded_account)
_ -> _ ->
"https://#{domain}/.well-known/webfinger?resource=acct:#{account}" "https://#{domain}/.well-known/webfinger?resource=#{encoded_account}"
end end
with response <- with response <-

12
mix.exs
View File

@ -4,7 +4,7 @@ defmodule Pleroma.Mixfile do
def project do def project do
[ [
app: :pleroma, app: :pleroma,
version: version("2.0.3"), version: version("2.0.4"),
elixir: "~> 1.8", elixir: "~> 1.8",
elixirc_paths: elixirc_paths(Mix.env()), elixirc_paths: elixirc_paths(Mix.env()),
compilers: [:phoenix, :gettext] ++ Mix.compilers(), compilers: [:phoenix, :gettext] ++ Mix.compilers(),
@ -63,7 +63,15 @@ def copy_nginx_config(%{path: target_path} = release) do
def application do def application do
[ [
mod: {Pleroma.Application, []}, mod: {Pleroma.Application, []},
extra_applications: [:logger, :runtime_tools, :comeonin, :quack, :fast_sanitize, :ssl], extra_applications: [
:logger,
:runtime_tools,
:comeonin,
:quack,
:fast_sanitize,
:ssl,
:eldap
],
included_applications: [:ex_syslogger] included_applications: [:ex_syslogger]
] ]
end end

View File

@ -30,7 +30,7 @@ def change do
Repo, Repo,
"select distinct unnest(nonexistent_locals.recipients) from activities, lateral (select array_agg(recipient) as recipients from unnest(activities.recipients) as recipient where recipient similar to '#{ "select distinct unnest(nonexistent_locals.recipients) from activities, lateral (select array_agg(recipient) as recipients from unnest(activities.recipients) as recipient where recipient similar to '#{
instance_uri instance_uri
}/users/[A-Za-z0-9]*' and not(recipient in (select ap_id from users where local = true))) nonexistent_locals;", }/users/[A-Za-z0-9]*' and not(recipient in (select ap_id from users))) nonexistent_locals;",
[], [],
timeout: :infinity timeout: :infinity
) )

View File

@ -211,7 +211,7 @@ def get(
end end
def get( def get(
"https://squeet.me/xrd/?uri=lain@squeet.me", "https://squeet.me/xrd/?uri=acct:lain@squeet.me",
_, _,
_, _,
Accept: "application/xrd+xml,application/jrd+json" Accept: "application/xrd+xml,application/jrd+json"
@ -850,7 +850,7 @@ def get(
end end
def get( def get(
"https://social.heldscal.la/.well-known/webfinger?resource=shp@social.heldscal.la", "https://social.heldscal.la/.well-known/webfinger?resource=acct:shp@social.heldscal.la",
_, _,
_, _,
Accept: "application/xrd+xml,application/jrd+json" Accept: "application/xrd+xml,application/jrd+json"
@ -863,7 +863,7 @@ def get(
end end
def get( def get(
"https://social.heldscal.la/.well-known/webfinger?resource=invalid_content@social.heldscal.la", "https://social.heldscal.la/.well-known/webfinger?resource=acct:invalid_content@social.heldscal.la",
_, _,
_, _,
Accept: "application/xrd+xml,application/jrd+json" Accept: "application/xrd+xml,application/jrd+json"
@ -880,7 +880,7 @@ def get("http://framatube.org/.well-known/host-meta", _, _, _) do
end end
def get( def get(
"http://framatube.org/main/xrd?uri=framasoft@framatube.org", "http://framatube.org/main/xrd?uri=acct:framasoft@framatube.org",
_, _,
_, _,
Accept: "application/xrd+xml,application/jrd+json" Accept: "application/xrd+xml,application/jrd+json"
@ -939,7 +939,7 @@ def get("http://gerzilla.de/.well-known/host-meta", _, _, _) do
end end
def get( def get(
"https://gerzilla.de/xrd/?uri=kaniini@gerzilla.de", "https://gerzilla.de/xrd/?uri=acct:kaniini@gerzilla.de",
_, _,
_, _,
Accept: "application/xrd+xml,application/jrd+json" Accept: "application/xrd+xml,application/jrd+json"
@ -1135,7 +1135,7 @@ def get("http://404.site" <> _, _, _, _) do
end end
def get( def get(
"https://zetsubou.xn--q9jyb4c/.well-known/webfinger?resource=lain@zetsubou.xn--q9jyb4c", "https://zetsubou.xn--q9jyb4c/.well-known/webfinger?resource=acct:lain@zetsubou.xn--q9jyb4c",
_, _,
_, _,
Accept: "application/xrd+xml,application/jrd+json" Accept: "application/xrd+xml,application/jrd+json"
@ -1148,7 +1148,7 @@ def get(
end end
def get( def get(
"https://zetsubou.xn--q9jyb4c/.well-known/webfinger?resource=https://zetsubou.xn--q9jyb4c/users/lain", "https://zetsubou.xn--q9jyb4c/.well-known/webfinger?resource=acct:https://zetsubou.xn--q9jyb4c/users/lain",
_, _,
_, _,
Accept: "application/xrd+xml,application/jrd+json" Accept: "application/xrd+xml,application/jrd+json"

View File

@ -652,9 +652,25 @@ test "it returns an announce activity in a collection", %{conn: conn} do
assert response(conn, 200) =~ announce_activity.data["object"] assert response(conn, 200) =~ announce_activity.data["object"]
end end
end
test "it rejects posts from other users", %{conn: conn} do describe "POST /users/:nickname/outbox (C2S)" do
data = File.read!("test/fixtures/activitypub-client-post-activity.json") |> Poison.decode!() setup do
[
activity: %{
"@context" => "https://www.w3.org/ns/activitystreams",
"type" => "Create",
"object" => %{"type" => "Note", "content" => "AP C2S test"},
"to" => "https://www.w3.org/ns/activitystreams#Public",
"cc" => []
}
]
end
test "it rejects posts from other users / unauthenticated users", %{
conn: conn,
activity: activity
} do
user = insert(:user) user = insert(:user)
otheruser = insert(:user) otheruser = insert(:user)
@ -662,39 +678,76 @@ test "it rejects posts from other users", %{conn: conn} do
conn conn
|> assign(:user, otheruser) |> assign(:user, otheruser)
|> put_req_header("content-type", "application/activity+json") |> put_req_header("content-type", "application/activity+json")
|> post("/users/#{user.nickname}/outbox", data) |> post("/users/#{user.nickname}/outbox", activity)
assert json_response(conn, 403) assert json_response(conn, 403)
end end
test "it inserts an incoming create activity into the database", %{conn: conn} do test "it inserts an incoming create activity into the database", %{
data = File.read!("test/fixtures/activitypub-client-post-activity.json") |> Poison.decode!() conn: conn,
activity: activity
} do
user = insert(:user) user = insert(:user)
conn = result =
conn conn
|> assign(:user, user) |> assign(:user, user)
|> put_req_header("content-type", "application/activity+json") |> put_req_header("content-type", "application/activity+json")
|> post("/users/#{user.nickname}/outbox", data) |> post("/users/#{user.nickname}/outbox", activity)
|> json_response(201)
result = json_response(conn, 201)
assert Activity.get_by_ap_id(result["id"]) assert Activity.get_by_ap_id(result["id"])
assert result["object"]
assert %Object{data: object} = Object.normalize(result["object"])
assert object["content"] == activity["object"]["content"]
end end
test "it rejects an incoming activity with bogus type", %{conn: conn} do test "it rejects anything beyond 'Note' creations", %{conn: conn, activity: activity} do
data = File.read!("test/fixtures/activitypub-client-post-activity.json") |> Poison.decode!()
user = insert(:user) user = insert(:user)
data = activity =
data activity
|> Map.put("type", "BadType") |> put_in(["object", "type"], "Benis")
_result =
conn
|> assign(:user, user)
|> put_req_header("content-type", "application/activity+json")
|> post("/users/#{user.nickname}/outbox", activity)
|> json_response(400)
end
test "it inserts an incoming sensitive activity into the database", %{
conn: conn,
activity: activity
} do
user = insert(:user)
object = Map.put(activity["object"], "sensitive", true)
activity = Map.put(activity, "object", object)
result =
conn
|> assign(:user, user)
|> put_req_header("content-type", "application/activity+json")
|> post("/users/#{user.nickname}/outbox", activity)
|> json_response(201)
assert Activity.get_by_ap_id(result["id"])
assert result["object"]
assert %Object{data: object} = Object.normalize(result["object"])
assert object["sensitive"] == activity["object"]["sensitive"]
assert object["content"] == activity["object"]["content"]
end
test "it rejects an incoming activity with bogus type", %{conn: conn, activity: activity} do
user = insert(:user)
activity = Map.put(activity, "type", "BadType")
conn = conn =
conn conn
|> assign(:user, user) |> assign(:user, user)
|> put_req_header("content-type", "application/activity+json") |> put_req_header("content-type", "application/activity+json")
|> post("/users/#{user.nickname}/outbox", data) |> post("/users/#{user.nickname}/outbox", activity)
assert json_response(conn, 400) assert json_response(conn, 400)
end end